273 lines
8.0 KiB
Bash

#!/usr/bin/env sh
#
# Blaze - record screen and audio
# Author - Cherrry9
deps() {
[ "$1" ] && {
md="$(for i in $deps; do printf " - \033[31m%s\033[0m\n" "$i"; done)"
printf "\033[31mYou are missing dependencies\033[0m\n"
printf "%b\n" "$md"
printf "\n"
}
printf "\033[34mRequired dependencies\033[0m\n"
printf " - \033[34mffmpeg\033[0m Actually recording\n"
printf " - \033[34mdmenu\033[0m Selecting the options\n"
printf "\n"
printf "\033[35mAt least one of these is required\033[0m\n"
printf " - \033[35mxorg-xrandr\033[0m Selecting a display to record\n"
printf " - \033[35mslop\033[0m Selecting an area to record\n"
printf "\n"
printf "\033[32mOptional dependencies\033[0m\n"
printf " - \033[32mnotify-send\033[0m Letting the user know when the recording starts/ends\n"
printf " - \033[32mxdg-desktop-dir\033[0m Use directory from xdg instead \$HOME/Videos\n"
exit
}
# check all necessary dependencies
_() { command -v "$1" >/dev/null 2>&1; }
_ dmenu || deps="$deps dmenu"
_ ffmpeg || deps="$deps ffmpeg"
_ xrandr || _ slop || deps="$deps xorg-xrandr/slop"
[ "$deps" ] && deps "$deps"
# output file, use $BLAZE_DIR and $BLAZE_FILE if they are set
if [ ! "$BLAZE_DIR" ]; then
_ xdg-user-dir &&
BLAZE_DIR=$(xdg-user-dir VIDEOS 2>/dev/null) ||
BLAZE_DIR="$HOME/Videos"
fi
[ ! -d "$BLAZE_DIR" ] && mkdir -p "$BLAZE_DIR" >/dev/null 2>&1
output="$BLAZE_DIR/${BLAZE_FILE:-blaze-$(date '+%Y-%m-%d_%H-%M-%S').mp4}"
# menu to use
m() { ${DMENU:-dmenu} "$@"; }
# exit if X isn't running
[ ! "$DISPLAY" ] && { echo "Can't open display; exiting"; exit; }
# find default audio device
audio() {
pacmd="$(pacmd list-sources | grep -i -B 1 output)"
dev="$(echo "$pacmd" | grep -i '\* index' ||
echo "$pacmd" | grep -i 'index' | head -n 1)"
audio="-f pulse -i $(echo "$dev" | grep -o '[0-9]')"
}
save() {
if [ -f "/tmp/blaze-pid" ]; then
recpid="$(cat /tmp/blaze-pid)"
# kill with SIGTERM, allowing finishing touches.
kill -15 "$recpid"
rm -f /tmp/blaze-pid
# even after SIGTERM, ffmpeg may still run, so SIGKILL it.
( sleep 3; kill -9 "$recpid" ) >/dev/null 2>&1 &
echo "Recording Stopped"
notify-send -t 2000 "Recording Stopped"
exit
else
echo "Recording isn't active"
notify-send -t 2000 "Recording isn't active"
exit 1
fi
}
help() {
printf "\033[34mOptions\033[0m\n"
printf " \033[34m-o\033[0m \033[35m[]\033[0m Specify the output file\n"
printf " \033[34m-s\033[0m End the recording\n"
printf " \033[34m-h\033[0m Display what you're reading right now\n"
printf " \033[34m-d\033[0m printf dependencies\n"
printf " \033[34m-c\033[0m Don't ask if the user is ready to record\n"
printf " \033[34m-p\033[0m \033[35m[]\033[0m Save to and load from preset <x>\n"
printf " \033[34m-r\033[0m \033[35m[]\033[0m Force framerate\n"
printf " \033[34m-b\033[0m \033[35m[]\033[0m Force bitrate (in MB)\n"
printf " \033[34m-m\033[0m \033[35m[]\033[0m Force method (slop, display)\n"
printf " \033[34m-d\033[0m \033[35m[]\033[0m Force display (Doesn't require -m)\n"
printf " \033[34m-n\033[0m Force disable NVENC\n"
printf " \033[34m-S\033[0m Options to use for slop (Needs to be quoted)\n"
printf " \033[34m-a\033[0m Record desktop audio\n"
printf "\n"
printf "To select an area, install 'slop',\n"
printf "to select a display, install 'xorg-xrandr'\n"
printf "\n"
printf "\033[35m[]\033[0m = Option requires an argument\n"
printf "\n"
printf "\033[34mVariables\033[0m\n"
printf " \033[34mBLAZE_DIR\033[0m Location to save the video\n"
printf " \033[37mDefault: xdg-user-dir VIDEOS or \$HOME/Videos\033[0m\n"
printf "\n"
printf " \033[34mBLAZE_FILE\033[0m Name of the saved video\n"
printf " \033[37mDefault: blaze-%s.mp4\033[0m\n" "\$(date +%Y-%m-%d_%H-%M-%S)"
printf "\n"
printf " \033[34mBLAZE_SLOP\033[0m Options to use for slop\n"
printf " \033[37mDefault: None\033[0m\n"
exit
}
while getopts ':hdscb:m:r:nD:S:p:ao:' opt; do
case "$opt" in
h)
help;;
d)
deps;;
s)
save;;
c)
ready='yes';;
b)
bitrate="-b:v ${OPTARG}M";;
m)
method="$OPTARG";;
r)
rate="$OPTARG";;
n)
nvenc=' ';;
D)
display="$OPTARG"
method='display';;
S)
sloptions="$OPTARG"
method='selection';;
p)
preset="$OPTARG";;
a)
audio;;
o)
output="$OPTARG";;
\?)
echo "Invalid Option: -$OPTARG" 1>&2
exit 1;;
:)
echo "Invalid Option: -$OPTARG requires an argument" 1>&2
exit 1;;
esac
done
shift $((OPTIND -1))
# exit if blaze is running
[ -f /tmp/blaze-pid ] && {
echo "Blaze is already running, exiting."
notify-send "Blaze is already running, exiting."
exit
}
[ "$preset" ] && {
# create preset location
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}"
# load preset
preset_location="${XDG_CONFIG_HOME:-$HOME/.config}"/blaze/"$preset"
[ -f "$preset_location" ] &&
. "$preset_location"
}
# ask the user what method they want to use
[ ! "$method" ] && {
# Check if the user has slop and disputils
_ slop && s=s
_ xrandr && d=d
# if the user only has slop or disputils (But not both) use that
[ "$s" ] && method=selection
[ "$d" ] && method=display
# if the user has both slop and disputils ask the user which one to use
[ "$s" ] && [ "$d" ] &&
method="$(printf "display\nselection" | m -p "Method of recording")"
}
if [ "$method" = display ]; then
# get information about the display
monitors="$(xrandr --listmonitors | awk 'NR>1 { printf $NF"\n" }')"
# if there's only one display, use that and skip asking
if [ "$(printf "%b\n" "$monitors" | wc -l)" = 1 ]; then
display="$monitors"
else # if there are other displays ask the user which one to use
[ ! "$display" ] && display="$(printf "%b" "$monitors" | m -p "Display to record")"
fi
set -- $(xrandr -q | grep "$display" | grep -oP '\d*x\d*\+\d*\+\d*' | tr '+x' ' ')
width="$1"
height="$2"
offX="$3"
offY="$4"
elif [ "$method" = selection ] || [ "$method" = slop ]; then
# select an area and make each number a separate word
set -- $(slop $sloptions -f '%w %h %x %y')
# get information about the display
width="$1"
height="$2"
offX="$3"
offY="$4"
[ "$(( width % 2 ))" = 1 ] && width="$(( width + 1 ))"
[ "$(( height % 2 ))" = 1 ] && height="$(( height + 1 ))"
else
printf "Invalid method; exiting\n"
exit 1
fi
# detect if the user has a nvidia card and use nvenc
[ ! "$nvenc" ] && lspci | grep -qi nvidia && nvenc="-vcodec h264_nvenc"
# ask the user what they want the framerate of the video to be
[ ! "$rate" ] && rate="$(printf "30\n60" | m -p "Framerate")"
[ ! "$rate" ] && exit
# ask the user if they want to start the recording
[ ! "$ready" ] && ready="$(printf "yes\nno" | m -p "Start the recording")"
# save preset
[ "$preset_location" ] && {
cat >"$preset_location"<<EOF
[ ! "\$rate" ] && rate="$rate"
[ ! "\$bitrate" ] && bitrate="$bitrate"
[ ! "\$method" ] && method="$method"
EOF
}
[ "$ready" = yes ] && {
notify-send -t 1500 "Recording Started"
# -loglevel error | makes ffmpeg only printf errors to the terminal
# -y | don't ask to start
# -draw_mouse 1 | show the mouse in the video
# -s | specifies the size of the recording
# -r "$rate" | specifies the framerate of the video
# -i | the input X display (not physical monitor) and offset
# -pix_fmt yuv420p | allows the video to be played on browsers like firefox
# -q:v | changes the quality of the video, lower is better.
# "$output" | file to save the recording to
ffmpeg \
-loglevel error \
-y \
$audio \
-f x11grab \
-draw_mouse 1 \
-s "${width}x$height" \
-r "$rate" \
-i "$DISPLAY.0+$offX,$offY" \
$bitrate \
-pix_fmt yuv420p \
$nvenc \
-q:v 0 \
"$output" &
echo $! > /tmp/blaze-pid
}