aboutsummaryrefslogtreecommitdiffstats
path: root/.config/init/funcs
diff options
context:
space:
mode:
Diffstat (limited to '.config/init/funcs')
-rwxr-xr-x.config/init/funcs/audio-concat127
-rwxr-xr-x.config/init/funcs/audio-convert233
-rwxr-xr-x.config/init/funcs/mpd-cover-convert8
-rwxr-xr-x.config/init/funcs/scap4
4 files changed, 368 insertions, 4 deletions
diff --git a/.config/init/funcs/audio-concat b/.config/init/funcs/audio-concat
new file mode 100755
index 0000000..73b3ae7
--- /dev/null
+++ b/.config/init/funcs/audio-concat
@@ -0,0 +1,127 @@
+#!/usr/bin/env zsh
+# concatenate multiple audio files into one
+
+source "$HOME/.config/init/helpers" || exit 1
+
+local callstr=$0
+
+usage() {
+ echo "Usage: $callstr [OPTIONS...] <infile>..."
+ echo "Concatenate multiple audio files into one"
+ echo ""
+ echo " \e[1mdescription opt longform arg default\e[0m"
+ echo " specify destination file -o --outfile <file> out.ogg"
+ echo " specify output bitrate -b --bitrate <int>k (opus:35k, vorbis:50k, mp3:65k, flac:N/A)"
+ echo " workaround for many inputs -m --many"
+ echo " print this help -h --help"
+ exit 0
+}
+
+trap_abort() {
+ echo ""
+ abort "process interrupted"
+}
+
+trap 'trap_abort' SIGABRT SIGHUP SIGINT SIGQUIT SIGTERM
+
+local dest='out.opus'
+
+local destpat='^.*\.(opus|mp3|ogg|flac)$'
+local bitratepat='^[1-9][0-9]*k$'
+
+local filterstr
+local codecstr
+local bitratestr
+local many
+
+local parseerr=$(2>&1 zparseopts -D -E -M -A args \
+ o: -outfile:=o \
+ b: -bitrate:=b \
+ m -many=m \
+ h -help=h | cut -d ' ' -f 2-)
+
+[[ -z $parseerr ]] || abort $parseerr
+
+zparseopts -D -E -M -A args \
+ o: -outfile:=o \
+ b: -bitrate:=b \
+ m -many=m \
+ h -help=h
+
+local optarg
+for opt in ${(@k)args}; do
+ unset optarg
+ [[ -z $args[$opt] ]] || optarg=$args[$opt]
+ case $opt in
+ -o) [[ $optarg =~ $destpat ]] || \
+ abort "destination file must be of type opus, mp3, or ogg"
+ dest=$optarg
+ [[ ${optarg:e} == 'opus' ]] && codecstr='libopus' \
+ && [[ -z $bitratestr ]] && bitratestr='35k'
+ [[ ${optarg:e} == 'mp3' ]] && codecstr='libmp3lame' \
+ && [[ -z $bitratestr ]] && bitratestr='65k'
+ [[ ${optarg:e} == 'ogg' ]] && codecstr='libvorbis' \
+ && [[ -z $bitratestr ]] && bitratestr='50k'
+ [[ ${optarg:e} == 'flac' ]] && codecstr='flac' \
+ && [[ -z $bitratestr ]] && bitratestr=''
+ ;;
+ -b) [[ $optarg =~ $bitratepat ]] || \
+ abort "bitrate must positive integer + k, for kbps"
+ bitratestr=$optarg
+ ;;
+ -m) many=true ;;
+ -h) usage ;;
+ esac
+done
+
+[[ -z $codecstr ]] && codecstr='libopus'
+[[ -z $bitratestr ]] && bitratestr='35k'
+
+[[ $codecstr == "flac" ]] && bitratestr=''
+
+[[ ${#@} -eq 0 ]] && abort "no input files specified"
+
+if [[ -e $dest ]]; then
+ local delprompt
+ printf "destination file \`$dest\` exists\ndelete it? [y/N]: "
+ read -q delprompt
+ echo ""
+ [[ $delprompt = "y" ]] || return 0
+ 2>/dev/null rm $dest || abort "could not delete file \`$dest\`"
+fi
+
+local pid
+
+if [[ -z $many ]]; then
+ local inputlist=()
+ local i=0
+ for f in $@; do
+ inputlist+=(-i $f)
+ filterstr="${filterstr}[${i}:a:0] "
+ i=$((i+1))
+ done
+
+ filterstr="${filterstr}concat=n=${i}:v=0:a=1 [outa]"
+
+ (
+ ffmpeg -loglevel -8 $inputlist \
+ -filter_complex $filterstr -map '[outa]' \
+ -c:a $codecstr ${bitratestr/*k/-b:a} $bitratestr \
+ -map_metadata -1 $dest
+ ) &
+ pid=$!
+else
+ (
+ for f in $@; do
+ ffmpeg -loglevel -8 -i $f -f s16le -ar 44.1k -ac 2 pipe:
+ done | ffmpeg -loglevel -8 -f s16le -ar 44.1k -ac 2 -i pipe: \
+ -c:a $codecstr ${bitratestr/*k/-b:a} $bitratestr \
+ -map_metadata -1 $dest
+ ) &
+ pid=$!
+fi
+
+local plural
+[[ $#@ -ne 1 ]] && plural='s'
+
+wait-anim $pid "concatenating $#@ file$plural to \`$dest\`"
diff --git a/.config/init/funcs/audio-convert b/.config/init/funcs/audio-convert
new file mode 100755
index 0000000..4923baa
--- /dev/null
+++ b/.config/init/funcs/audio-convert
@@ -0,0 +1,233 @@
+#!/usr/bin/env zsh
+# concatenate multiple audio files into one
+
+source "$HOME/.config/init/helpers" || exit 1
+
+local callstr=$0
+
+usage() {
+ echo "Usage: $callstr [OPTIONS...] <infile>..."
+ echo "Convert multiple audio files to a new format"
+ echo ""
+ echo " \e[1mdescription opt longform arg default\e[0m"
+ echo " output codec -c --codec <codec> opus"
+ echo " output bitrate -b --bitrate <int>k (opus:35k, vorbis:50k, mp3:65k, flac:N/A)"
+ echo " output quality -q --quality <int> N/A"
+ echo " output directory -d --dest <dir> ."
+ echo " copy metadata -m --metadata <bool> false"
+ echo " background job count -j --jobs <int> 4"
+ echo " print this help -h --help"
+ exit 0
+}
+
+local fifoname
+local fifomade=0
+local pid
+
+trap_abort() {
+ echo ""
+ print-error "process interrupted"
+ # race condition-y, but eh
+ repeat 5; do
+ [[ -z $pid ]] && sleep 0.1 || break
+ done
+ [[ -z $pid ]] || kill -s SIGKILL $pid
+ [[ -p $fifoname ]] && [[ $fifomade -eq 1 ]] && 2>/dev/null rm $fifoname
+ exit 1
+}
+
+trap 'trap_abort' SIGABRT SIGHUP SIGINT SIGQUIT SIGTERM
+
+local codecpat='^(opus|mp3|vorbis|flac)$'
+local bitratepat='^[1-9][0-9]*k$'
+local metadatapat='^(true|false)$'
+local jobcountpat='^[1-9][0-9]*$'
+
+local qpatvorbis='^([0-9]|10)$'
+local qpatmp3='^[0-9]$'
+
+local codecstr
+local codecprintstr
+local extstr
+local bitratestr
+local bitrateset
+local metastr
+local dirstr
+local qstr
+
+local jobcount
+
+local parseerr=$(2>&1 zparseopts -D -E -M -A args \
+ c: -codec:=c \
+ b: -bitrate:=b \
+ q: -quality:=q \
+ d: -dest:=d -destination:=d \
+ j: -jobs:=j \
+ m:: -metadata::=m \
+ h -help=h | cut -d ' ' -f 2-)
+
+[[ -z $parseerr ]] || abort $parseerr
+
+zparseopts -D -E -M -A args \
+ c: -codec:=c \
+ b: -bitrate:=b \
+ q: -quality:=q \
+ d: -dest:=d -destination:=d \
+ j: -jobs:=j \
+ m:: -metadata::=m \
+ h -help=h
+
+local optarg
+local opt
+for opt in ${(@k)args}; do
+ unset optarg
+ [[ -z $args[$opt] ]] || optarg=$args[$opt]
+ case $opt in
+ -c) [[ $optarg =~ $codecpat ]] || \
+ abort "codec must be one of \`opus\`, \`mp3\`, \`flac\`, or \`vorbis\`"
+ [[ ${optarg} == 'opus' ]] \
+ && codecprintstr=${optarg} \
+ && codecstr='libopus' && extstr='opus' \
+ && [[ -z $bitratestr ]] && bitratestr='35k'
+ [[ ${optarg} == 'mp3' ]] \
+ && codecprintstr=${optarg} \
+ && codecstr='libmp3lame' && extstr='mp3' \
+ && [[ -z $bitratestr ]] && bitratestr='65k'
+ [[ ${optarg} == 'vorbis' ]] \
+ && codecprintstr=${optarg} \
+ && codecstr='libvorbis' && extstr='ogg' \
+ && [[ -z $bitratestr ]] && bitratestr='50k'
+ [[ ${optarg} == 'flac' ]] \
+ && codecprintstr=${optarg} \
+ && codecstr='flac' && extstr='flac' \
+ && [[ -z $bitratestr ]] && bitratestr=''
+ ;;
+ -b) [[ $optarg =~ $bitratepat ]] || \
+ abort "bitrate must positive integer + k, for kbps"
+ bitratestr=$optarg
+ bitrateset=1
+ ;;
+ -q) qstr=$optarg ;;
+ -d) dirstr=$optarg ;;
+ -j) [[ $optarg =~ $jobcountpat ]] || \
+ abort "job count must be a non-negative integer"
+ jobcount=$optarg
+ ;;
+ -m) if [[ $optarg ]]; then
+ [[ $optarg =~ $metadatapat ]] || \
+ abort "metadata must be either \`true\` or \`false\`"
+
+ [[ $optarg == "false" ]] && metastr="" \
+ || metastr=("-map_metadata" "-1")
+ else
+ metastr=("-map_metadata" "-1")
+ fi
+ ;;
+ -h) usage ;;
+ esac
+done
+
+[[ -z $codecstr ]] && codecstr='libopus'
+[[ -z $bitratestr ]] && bitratestr='35k'
+[[ -z $codecprintstr ]] && codecprintstr='opus'
+[[ -z $extstr ]] && extstr='opus'
+[[ -z $jobcount ]] && jobcount=4
+[[ -z $dirstr ]] && dirstr='.'
+[[ -z $metastr ]] && metastr=("-map_metadata" "-1")
+
+if [[ ! -z $qstr ]]; then
+ [[ -z $bitratset ]] || abort "-b and -q are not compatible"
+ [[ $codecstr == "libopus" ]] && abort "-q cannot be used with opus"
+ [[ $codecstr == "libflac" ]] && abort "-q cannot be used with flac"
+ [[ $codecstr == "libvorbis" ]] && [[ ! $qstr =~ $qpatvorbis ]] \
+ && abort "for vorbis, -q must be in the range [0-10]"
+ [[ $codecstr == "libmp3lame" ]] && [[ ! $qstr =~ $qpatmp3 ]] \
+ && abort "for mp3, -q must be in the range [0-9]"
+else
+fi
+
+[[ $codecstr == "flac" ]] && bitratestr=''
+
+[[ $#@ -eq 0 ]] && abort "no input files specified"
+
+local f
+for f in $@; do
+ [[ -f $f ]] || abort "could not read file \`$f\`"
+done
+
+2>/dev/null mkdir -p $dirstr || abort "could not write to directory \`$dirstr\`"
+
+repeat 5; do
+ fifoname="$dirstr/audio-convert-tmp-$RANDOM"
+ [[ -e $fifoname ]] && continue
+ 2>/dev/null mkfifo $fifoname || return 1
+ fifomade=1
+ break
+done
+
+[[ $fifomade -eq 1 ]] || abort "could not make temporary fifo"
+
+local delprompt
+for f in $@; do
+ local dest="$dirstr/${f:t:r}.$extstr"
+
+ if [[ -e $dest ]]; then
+ printf "destination file \`$dest\` exists\ndelete it? [y/N]: "
+ read -q delprompt
+ print ""
+ [[ $delprompt = "y" ]] || return 0
+ 2>/dev/null rm $dest || abort "could not delete file \`$dest\`"
+ fi
+done
+
+local totalstr="${#@} file"
+[[ $#@ -ne 1 ]] && totalstr="${totalstr}s"
+local jobstr=$jobcount
+[[ $#@ -lt $jobcount ]] && jobstr=$#@
+[[ $jobstr -gt 1 ]] && jobstr="${jobstr} jobs" || jobstr="${jobstr} job"
+
+(
+{
+ local joblist=()
+ while read -d $'\0' f; do
+ local dest="$dirstr/${f:t:r}.$extstr"
+ (
+ ffmpeg -loglevel -8 -i $f \
+ -vn -sn -c:a $codecstr \
+ ${bitratestr/*k/-b:a} $bitratestr \
+ ${qstr/[0-9]*/-q:a} $qstr \
+ $metastr \
+ $dest
+ echo "done"
+ ) &
+ joblist+=$!
+ done
+
+ local j
+ for j in $joblist; do
+ 2>/dev/null wait $j
+ done
+} < $fifoname | {
+ repeat $jobcount; do
+ if [[ $#@ -gt 0 ]]; then
+ printf "%s\0" $@[1]
+ shift
+ fi
+ done
+
+ while read line; do
+ if [[ $#@ -gt 0 ]]; then
+ printf "%s\0" $@[1]
+ shift
+ else
+ break
+ fi
+ done
+} > $fifoname
+)&
+
+pid=$!
+
+wait-anim $pid "using $jobstr to convert $totalstr to $codecprintstr"
+
+2>/dev/null rm $fifoname
diff --git a/.config/init/funcs/mpd-cover-convert b/.config/init/funcs/mpd-cover-convert
index e8359b7..d9d7a2c 100755
--- a/.config/init/funcs/mpd-cover-convert
+++ b/.config/init/funcs/mpd-cover-convert
@@ -3,10 +3,14 @@
# leaks memory for some reason, so don't run on a clean library
# or it'll crash everything
-local d
+source "$HOME/.config/init/helpers" || exit 1
+
+(local file
find ~/music -type f -regextype posix-extended -regex ".*cover\.(png|jpg)"\
| while read file; do
if [[ ! -f "${file:h}/cover-small.png" ]]; then
convert "$file" -resize 250x "${file:h}/cover-small.png"
fi
-done
+done) &
+
+wait-anim $! "converting"
diff --git a/.config/init/funcs/scap b/.config/init/funcs/scap
index 85a083f..f87eb93 100755
--- a/.config/init/funcs/scap
+++ b/.config/init/funcs/scap
@@ -7,8 +7,8 @@ xset q
archey3
sleep .2
-if [[ -f '/tmp/cap.mp4' ]]; then
- rm '/tmp/cap.mp4'
+if [[ -e '/tmp/cap.mp4' ]]; then
+ rm '/tmp/cap.mp4' || return 1
fi
echo 'recording...'