From 40ac41cff7293e520bae0c8790ef6694f45f19b7 Mon Sep 17 00:00:00 2001 From: katherine Date: Wed, 15 May 2019 10:43:54 -0700 Subject: fix audio-convert and helper functions --- .config/init/funcs/audio-convert | 50 +++++------ .config/init/helpers | 175 +++++++++++++++++++++------------------ 2 files changed, 117 insertions(+), 108 deletions(-) (limited to '.config/init') diff --git a/.config/init/funcs/audio-convert b/.config/init/funcs/audio-convert index 24c5d62..9d153d4 100755 --- a/.config/init/funcs/audio-convert +++ b/.config/init/funcs/audio-convert @@ -1,5 +1,5 @@ #!/usr/bin/env zsh -# concatenate multiple audio files into one +# use parallel jobs to convert audio files from one format to another source "$HOME/.config/init/helpers" || exit 1 @@ -24,21 +24,13 @@ 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 - exit 1 + abort "process interrupted" } 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]$' @@ -54,6 +46,7 @@ local qstr local jobcount +local args local parseerr=$(2>&1 zparseopts -D -E -M -A args \ c: -codec:=c \ b: -bitrate:=b \ @@ -61,6 +54,7 @@ local parseerr=$(2>&1 zparseopts -D -E -M -A args \ d: -dest:=d -destination:=d \ j: -jobs:=j \ m:: -metadata::=m \ + f:: -force::=f \ h -help=h | cut -d ' ' -f 2-) [[ -z $parseerr ]] || abort $parseerr @@ -72,6 +66,7 @@ zparseopts -D -E -M -A args \ d: -dest:=d -destination:=d \ j: -jobs:=j \ m:: -metadata::=m \ + f:: -force::=f \ h -help=h local optarg @@ -106,24 +101,26 @@ for opt in ${(@k)args}; do ;; -q) qstr=$optarg ;; -d) dirstr=$optarg ;; - -j) [[ $optarg =~ $jobcountpat ]] || \ + -j) [[ $optarg =~ $posunsignedpat ]] || \ 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 =~ $boolpat ]] || \ + abort "metadata must be a boolean value (e.g. \`true\` or \`false\`)" - [[ $optarg == "false" ]] && metastr="" \ + [[ $optarg =~ $booltpat ]] && metastr=("-map_metadata" "0") \ || metastr=("-map_metadata" "-1") else - metastr=("-map_metadata" "-1") + metastr=("-map_metadata" "0") fi ;; -h) usage ;; esac done +[[ $#@ -eq 0 ]] && abort "no input files specified" + [[ -z $codecstr ]] && codecstr='libopus' [[ -z $bitratestr ]] && bitratestr='35k' [[ -z $codecprintstr ]] && codecprintstr='opus' @@ -135,17 +132,17 @@ done 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 == "flac" ]] && 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" +if [[ $codecstr == "flac" ]]; then + bitratestr='' + [[ -z $bitrateset ]] || abort "-b cannot be used with flac" +fi local roots=(${@:t:r}) local uniqroots=(${(u)roots}) @@ -182,6 +179,7 @@ local jobstr=$jobcount coproc { local joblist=() + local c while read -d $'\0' c; do [[ $c == "done" ]] && break local f=${c:s/file:/} @@ -206,24 +204,20 @@ coproc { echo "done" } -pid=$! - repeat $jobcount; do if [[ $#@ -gt 0 ]]; then - 1>&p printf "%s\0" $@[1] + 1>&p printf "file:%s\0" $@[1] shift fi done while read -p line; do [[ $line == "done" ]] && coproc exit && break - echo "$line" + echo $line if [[ $#@ -gt 0 ]]; then - 1>&p printf "%s\0" "file:${@[1]}" + 1>&p printf "file:%s\0" $@[1] shift else - 1>&p printf "%s\0" "done" + 1>&p printf "done\0" fi done | progress-bar $filecount "using $jobstr to convert $totalstr to $codecprintstr" - -2>/dev/null wait $pid diff --git a/.config/init/helpers b/.config/init/helpers index 37ae17a..e1ac96e 100644 --- a/.config/init/helpers +++ b/.config/init/helpers @@ -1,3 +1,42 @@ +#!/usr/bin/env zsh + +# patterns for option matching +boolpat='^(true|yes|on|1|false|no|off|0)$' +booltpat='^(true|yes|on|1)$' +boolfpat='^(false|no|off|0)$' + +intpat='^[-+]?[0-9]+$' +unsignedpat='^[0-9]+$' +posunsignedpat='^[1-9][0-9]*$' +floatpat='^[-+]?[0-9]+(\.[0-9]*|e(0|[-+]?[1-9][0-9]*)|\.[0-9]*e(0|[-+]?[1-9][0-9]*$' + +termcolourpat='^(black|light_black|red|light_red|green|light_green|yellow|light_yellow|blue|light_blue|magenta|light_magenta|cyan|light_cyan|white|light_white)$' + +# $1 - colour +termcolourpat2escape() { + [[ $#@ -eq 1 ]] || {echo 'badcolour'; return 1} + [[ $1 =~ $termcolourpat ]] || {echo 'badcolour'; return 1} + + case $1 in + 'black') printf '\e[30m' ;; + 'light_black') printf '\e[1;30m' ;; + 'red') printf '\e[31m' ;; + 'light_red') printf '\e[1;31m' ;; + 'green') printf '\e[32m' ;; + 'light_green') printf '\e[1;32m' ;; + 'yellow') printf '\e[33m' ;; + 'light_yellow') printf '\e[1;33m' ;; + 'blue') printf '\e[34m' ;; + 'light_blue') printf '\e[1;34m' ;; + 'magenta') printf '\e[35m' ;; + 'light_magenta') printf '\e[1;35m' ;; + 'cyan') printf '\e[36m' ;; + 'light_cyan') printf '\e[1;36m' ;; + 'white') printf '\e[37m' ;; + 'light_white') printf '\e[1;37m' ;; + esac +} + # $1 - message print-error() { 1>&2 echo "\e[1;31merror:\e[0m $1" @@ -9,23 +48,41 @@ abort() { exit 1 } +# $1 - seconds +sec2time() { + zmodload zsh/datetime || return 1 + + if [[ $1 -lt 0 ]]; then + printf "??:??:??" + return 0 + fi + + if [[ $1 -lt 86400 ]]; then + TZ=UTC strftime '%H:%M:%S' $1 + return 0 + fi + + if [[ $1 -ge 8640000 ]]; then + printf "forever?" + return 0 + fi + + printf "~%02d days" "$(($1 / 86400))" +} + # $1 - count # $2 - message (opt) -# $3 - colourpat (opt) +# $3 - colour (opt) progress-bar() { - - zmodload zsh/datetime zsh/mathfunc || return 1 + zmodload zsh/mathfunc zsh/datetime || return 1 [[ $#@ -ne 0 ]] && [[ $#@ -lt 4 ]] || return 1 - local countpat='^[1-9][0-9]*$' - local colourpat='^(black|light_black|red|light_red|green|light_green|yellow|light_yellow|blue|light_blue|magenta|light_magenta|cyan|light_cyan|white|light_white)$' - local count - [[ $1 =~ $countpat ]] && count=$1 || return 1 - if [[ ! -z $3 ]]; then - [[ $3 =~ $colourpat ]] || return 1 - fi + [[ $1 =~ $posunsignedpat ]] && count=$1 || return 1 + [[ ! -z $3 ]] && { + [[ $3 =~ $termcolourpat ]] || return 1 + } local message local colour @@ -33,35 +90,19 @@ progress-bar() { [[ -z $2 ]] && message='waiting' || message=$2 [[ -z $3 ]] && colour='yellow' || colour=$3 - case $colour in - 'black') colour='\e[30m' ;; - 'light_black') colour='\e[1;30m' ;; - 'red') colour='\e[31m' ;; - 'light_red') colour='\e[1;31m' ;; - 'green') colour='\e[32m' ;; - 'light_green') colour='\e[1;32m' ;; - 'yellow') colour='\e[33m' ;; - 'light_yellow') colour='\e[1;33m' ;; - 'blue') colour='\e[34m' ;; - 'light_blue') colour='\e[1;34m' ;; - 'magenta') colour='\e[35m' ;; - 'light_magenta') colour='\e[1;35m' ;; - 'cyan') colour='\e[36m' ;; - 'light_cyan') colour='\e[1;36m' ;; - 'white') colour='\e[37m' ;; - 'light_white') colour='\e[1;37m' ;; - esac + colour=$(termcolourpat2escape $colour) local i=0 local starttime=$EPOCHREALTIME local lasttime=$starttime - local thistime=$starttime + local thistime=$starttime + local now=$starttime local elapsed=0 while true; do - - local now=$EPOCHREALTIME [[ $i -eq $count ]] && break + now=$EPOCHREALTIME + local width=$COLUMNS local statwidth=$(( ($#count * 2) + 35)) local progwidth=$(($width - $statwidth - 3)) @@ -70,19 +111,10 @@ progress-bar() { if [[ $i -eq 0 ]]; then eta='??:??:??' else - local left=$(( ($count - $i) * ($elapsed / $i) - ($now - $lasttime) )) - if [[ $left -ge 86400 ]]; then - eta=' days...' - elif [[ $left -le 0 ]]; then - eta='00:00:00' - else - eta=$(strftime '%H:%M:%S' ${$(( ceil($left + 802800) )):s/\./}) - fi + eta=$(sec2time ${$(( ceil( ($count - $i) * ($elapsed / $i) - ($now - $lasttime) ) )):s/\./}) fi - local rt=$(($now - $starttime)) - [[ $rt -ge 86400 ]] && rt=' days...' \ - || rt=$(strftime '%H:%M:%S' ${$(( floor($rt + 802800) )):s/\./}) + local rt=$(sec2time ${$(( floor( ($now - $starttime) ) )):s/\./} ) local fpart="" local epart="" @@ -96,7 +128,7 @@ progress-bar() { $i \ read -t 0.2 \ - && thistime=$EPOCHREALTIME \ + && thistime=$EPOCHREALTIME \ && elapsed=$(($elapsed - $lasttime + $thistime)) \ && lasttime=$thistime \ && i=$(($i + 1)) @@ -104,23 +136,21 @@ progress-bar() { printf "\e[F" done - [[ $i -eq $count ]] && echo "\e[G\e[32m$message... done!\e[0m\e[J" \ + [[ $i -eq $count ]] \ + && echo "\e[G\e[32m$message... done in $(sec2time ${$(( floor($elapsed) )):s/\./})\e[0m\e[J" \ || echo "\e[G\e[31m$message... failed!\e[0m\e[J" } # $1 - pid # $2 - message (opt) -# $3 - colourpat (opt) +# $3 - colour (opt) wait-anim() { [[ $#@ -ne 0 ]] && [[ $#@ -lt 4 ]] || return 1 - local pidpat='^[1-9][0-9]*$' - local colourpat='^(black|light_black|red|light_red|green|light_green|yellow|light_yellow|blue|light_blue|magenta|light_magenta|cyan|light_cyan|white|light_white)$' - - [[ $1 =~ $pidpat ]] || return 1 - if [[ ! -z $3 ]]; then - [[ $3 =~ $colourpat ]] || return 1 - fi + [[ $1 =~ $posunsignedpat ]] || return 1 + [[ ! -z $3 ]] && { + [[ $3 =~ $termcolourpat ]] || return 1 + } local message local colour @@ -128,28 +158,9 @@ wait-anim() { [[ -z $2 ]] && message='waiting' || message=$2 [[ -z $3 ]] && colour='yellow' || colour=$3 - case $colour in - 'black') colour='\e[30m' ;; - 'light_black') colour='\e[1;30m' ;; - 'red') colour='\e[31m' ;; - 'light_red') colour='\e[1;31m' ;; - 'green') colour='\e[32m' ;; - 'light_green') colour='\e[1;32m' ;; - 'yellow') colour='\e[33m' ;; - 'light_yellow') colour='\e[1;33m' ;; - 'blue') colour='\e[34m' ;; - 'light_blue') colour='\e[1;34m' ;; - 'magenta') colour='\e[35m' ;; - 'light_magenta') colour='\e[1;35m' ;; - 'cyan') colour='\e[36m' ;; - 'light_cyan') colour='\e[1;36m' ;; - 'white') colour='\e[37m' ;; - 'light_white') colour='\e[1;37m' ;; - esac + colour=$(termcolourpat2escape $colour) - local curframe local frames - case $(($RANDOM % 7)) in 0) frames=('▁' '▂' '▃' '▄' '▅' '▆' '▇' '█' '▇' '▆' '▅' '▄' '▃' '▂') ;; 1) frames=(' ' '▖' '▚' '▝' ' ' '▘' '▞' '▗') ;; @@ -160,19 +171,23 @@ wait-anim() { 6) frames=('O' 'o' '.' 'o') ;; esac - local rval - - { - wait $1 - rval=$? - echo "done" - } | while true; do + local curframe + coproc while true; do [[ -z $curframe ]] && curframe=0 - printf "\e[G\e[K|\e[1;32m${frames[$(($curframe + 1))]}\e[0m| $colour$message...\e[0m" + printf "\e[G\e[K|\e[1;32m${frames[$(($curframe + 1))]}\e[0m| $colour$message...\e[0m\n" curframe=$(( ($curframe + 1) % $#frames )) read -t 0.2 && break done + while read -p line; do + printf $line + done & + local printer=$! + + local rval + 2>/dev/null wait $1 && rval=$? && echo "done" >&p + 2>/dev/null wait $printer + [[ $rval -eq 0 ]] && printf "\e[G\e[K\e[32m$message... done!\e[0m\n" \ || printf "\e[G\e[K\e[31m$message... failed!\e[0m\n" -- cgit v1.2.3