From 156dd1aa0b0959a689ee86b4bef7b4c04d2a7117 Mon Sep 17 00:00:00 2001 From: Kimapr Date: Fri, 20 Dec 2024 18:44:16 +0500 Subject: [PATCH] perfo romantic --- play6 | 345 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 178 insertions(+), 167 deletions(-) diff --git a/play6 b/play6 index 96b7553..4aebe05 100755 --- a/play6 +++ b/play6 @@ -16,6 +16,7 @@ # # for example: # +# #!/usr/bin/env -S play6 play # collect \ # 100 epic_music.mp3 \ # 50 less_epic_music.webm @@ -53,138 +54,132 @@ mktfifo() { { mkfifo "$(printf "$(test -z "$TMPDIR" && printf '/tmp' || printf "%s" "$TMPDIR")/pipe.$(rand).$(rand)$1" | tee /dev/fd/3)"; } 3>&1 } -if (printf '' | base64) >/dev/null 2>&1; then - _list_enc() { - printf : - base64 -w0 - printf '\n' - } - _list_dec() { - printf '%s' "${1#:}" | base64 -d - } -else - _list_enc() { - printf : - od -An -b | sed -e 's/[0-9][0-9]*/\\0\0/g;s/\s//g' | tr -d '\n' - printf '\n' - } - _list_dec() { - printf '%b' "$(printf '%s' "${1#:}" | base64 -d)" - } -fi + +dyn_set() { eval "$(printf '_dyn__fn() { %s="$1"; }\n' "$1")"; + _dyn__fn "$2"; } +dyn_get() { eval "$(printf \ + '_dyn__fn() { test ! -z "${%s+x}" && %s="$%s"; }\n' "$2" "$1" "$2")"; + _dyn__fn; } +dyn_unset() { eval "$(printf '_dyn__fn() { unset %s; }\n' "$1")"; + _dyn__fn; } + +_list_id=0 list_mk() { + _list_id=$((_list_id+1)) + _list_mk_id="_arr_$_list_id" + dyn_set "$1" "$_list_mk_id" + shift 1 + dyn_set ${_list_mk_id}_len $# + _list_mk_i=0 for _list_mk_arg; do - printf '%s' "$_list_mk_arg" | _list_enc + _list_mk_i=$((_list_mk_i+1)) + dyn_set ${_list_mk_id}_${_list_mk_i} "$_list_mk_arg" done } -list_slice() { - [ $# = 2 ] || return 1 - if [ $1 -gt $2 ]; then - list_slice $2 $1; - return - fi - _list_slice_i=1 - while read -r line; do - if test $_list_slice_i -gt $2; then - break - fi - if test $_list_slice_i -ge $1; then - printf '%s\n' "$line" - fi - _list_slice_i=$((_list_slice_i+1)) +list_unmk() { + _list_unmk_i=0 + dyn_get _list_unmk_id $1 || return + dyn_get _list_unmk_len ${_list_unmk_id}_len || return + while [ $_list_unmk_i != $_list_unmk_len ]; do + _list_unmk_i=$((_list_unmk_i+1)) + dyn_unset ${_list_unmk_id}_${list_unmk_i} done - unset _list_slice_i -} -list_len() { - tr -cd : | wc -c + dyn_unset ${_list_unmk_id}_len } list_get() { - list_slice $1 $1 | list_xargs printf '%s' + dyn_get _list_get_id "$1" || return + [ "$2" -eq "$2" ] || return + dyn_get "$3" "${_list_get_id}_$2" } -inarg() { - _inarg_arg="$1" - shift 1 - printf '%s\n' "$(printf '%s' "$_inarg_arg")" | "$@" - unset _inarg_arg +list_len() { + dyn_get _list_len_id $1 || return + dyn_get _list_len_len ${_list_len_id}_len || return + printf '%s\n' $_list_len_len } -list_xargs() { - while read -r _list_xargs_arg; do - _list_xargs_arg="$(_list_dec "$_list_xargs_arg"; echo :)" - _list_xargs_arg="${_list_xargs_arg%:}" - set -- "$@" "$_list_xargs_arg" +list_resize() { + dyn_get _list_resize_id $1 || return + [ "$2" -eq "$2" ] || return + [ $2 -ge 0 ] || return + dyn_get _list_resize_len ${_list_resize_id}_len || return + _list_resize_i=$_list_resize_len + while [ "$_list_resize_i" -gt "$2" ]; do + dyn_unset ${_list_resize_id}_${_list_resize_i} + _list_resize_i=$((_list_resize_i-1)) done - unset _list_xargs_arg - "$@" + _list_resize_i=$((_list_resize_len+1)) + while [ "$_list_resize_i" -le "$2" ]; do + dyn_set ${_list_resize_id}_${_list_resize_i} "" + _list_resize_i=$((_list_resize_i+1)) + done + dyn_set ${_list_resize_id}_len "$2" +} +list_set() { + dyn_get _list_set_id "$1" || return + [ "$2" -eq "$2" ] || return + dyn_get _list_set_len ${_list_set_id}_len || return + if [ "$2" -gt "$_list_set_len" ]; then + list_resize "$1" "$2" || return + fi + dyn_set "${_list_set_id}_$2" "$3" +} +list_push() { + list_resize "$1" "$(("$(list_len $1)" +1))" || return + list_set "$1" "$(list_len $1)" "$2" } list_pop() { - read -r _list_pop_line || return - inarg "$_list_pop_line" list_xargs printf '%s' -} -list_pack() { - [ $1 -ge 1 ] || return - _list_pack_spl=$1 - while :; do - read -r line || break - set -- "$line" - i=$_list_pack_spl - while test $i -gt 1; do - read -r line || return - set -- "$@" "$line" - i=$((i - 1)) - done - for line; do - printf '%s\n' "$line" - done | _list_enc || return - done + list_get "$1" "$(list_len $1)" "$2" || return + list_resize "$1" "$(($(list_len $1)-1))" } + collect() { _collect_fifo_lens="$(mktfifo)" _collect_gen() { i=0; - _collect_on() { - _name="$(inarg "$1" list_get 2; echo :)"; _name="${_name%:}" - } { while :; do - _name="$(list_pop && echo :)" || break + { ! test -z ${1+x}; } || break + { ! test -z ${2+x}; } || return + _name="$2" + _weight="$1" + shift 2 i=$((i+1)); ( - _name="${_name%:}" - _name="$(inarg "$_name" list_get 2; echo :)" - _name="${_name%:}" printf "%d %.0f\n" $i \ "$(if test -e "$_name" then + printf 'info: probe "%s"\n' "$_name" >&2 ffprobe -loglevel 8 -of flat -show_entries format=duration "$_name" | sed 's/^[^"]*"\([^"]*\)"$/\1/' + printf 'info: DONE probe "%s"\n' "$_name" >&2 else printf 'warn: "%s": file not found\n' "$_name" >&2 echo -1 fi)" ) & - done; wait; } | sort -n | sed 's/^[0-9]* *//' | while read line; do - list_mk "$line" - done + done; wait; } | sort -n | sed 's/^[0-9]* *//' } - list_mk "$@" | list_pack 2 | _collect_gen > "$_collect_fifo_lens" & - _collect_fn() { - for _arg; do - _weight="$(inarg "$_arg" list_get 1; echo :)"; _weight="${_weight%:}" - _name="$(inarg "$_arg" list_get 2; echo :)"; _name="${_name%:}" - _len="$(list_pop <&3)" || exit - if [ "$_len" -ge 0 ]; then - _newf="$(list_mk "$_name" "$_weight" "$_len"; echo :)"; - _newf="${_newf%:}"; list_mk "$_newf" - fi - done - } - list="$(list_mk "$@" | list_pack 2 | - list_xargs _collect_fn 3<"$_collect_fifo_lens")" + _collect_gen "$@" > "$_collect_fifo_lens" & + list_mk list + while true; do + { ! test -z ${1+x}; } || break + { ! test -z ${2+x}; } || exit + read -r _collect_len + list_mk _collect_entry "$2" "$1" "$_collect_len" + list_push list "$_collect_entry" + test -z "$_collect_lpi" && { _collect_lpi=1; printf 'info: collecting' >&2; } + printf '.' >&2 + shift 2 + done < "$_collect_fifo_lens" + printf '\n' >&2 rm "$_collect_fifo_lens" - unset _collect_fifo_lens - unset _collect_fn - unset _collect_gen - if test $(inarg "$list" list_len) = 0; then + if ! test "$(list_len list)" -gt 0; then printf 'fatal: no music\n' >&2 exit 1 fi + for i in $(seq 1 $(list_len list) ); do + list_get list $i entry + list_get entry 1 name + list_get entry 2 weight + list_get entry 3 len + printf 'info: (%s): %sx %ss\n' "$name" "$weight" "$len" >&2; + done } if test -e /dev/urandom; then rand() { echo $(head -c4 /dev/urandom | od -An -t u); } @@ -204,71 +199,78 @@ randn() { done printf $(($_rand % $1))) } -gen() { - (_f() { - _ff() { - printf '{\n\tname: %s\n\tweight: %sx\n\tlen: %ss\n}\n' "$@" >&2 - } - for arg; do - inarg "$arg" list_xargs _ff - done - };inarg "$list" list_xargs _f) - _len="$(inarg "$list" list_len)" +gen() ( + _len="$(list_len list)" echo count: $_len >&2 - _maxll="$(_len_f() { - mll="$(inarg "$1" list_get 3)" - shift 1; - for arg; do - num="$(inarg "$arg" list_get 3)" - if [ "$num" -ge "$mll" ]; then - mll="$num" - fi - done - echo $mll - }; inarg "$list" list_xargs _len_f)" + _get_el() { + list_get list "$1" _entry || return + list_get _entry 3 "$2" + } + _get_el 1 _maxll || return + for i in $(seq 2 $(list_len list)); do + _get_el $i _mll + if [ "$_mll" -gt "$_maxll" ]; then + _maxll="$_mll" + fi + done echo maxlen: $_maxll >&2 - _weight="$(wei=0 - _onlist(){ - for arg; do - _name="$(inarg "$arg" list_get 1; echo :)"; _name="${_name%:}" - _vwei="$(inarg "$arg" list_get 2; echo :)"; _vwei="${_vwei%:}" - _vlen="$(inarg "$arg" list_get 3; echo :)"; _vlen="${_vlen%:}" - prevwei=$wei; - wei=$((wei+(((10000 * _maxll) / _vlen) * _vwei))) - printf 'chance: %s\n' $((wei-prevwei)) >&2 - _newf="$(list_mk "$_name" "$wei"; echo :)"; - _newf="${_newf%:}"; list_mk "$_newf" - done - } - inarg "$list" list_xargs _onlist - echo :)"; _weight="${_weight%:}" - maxwei="$(_mw_fn(){ - shift $(($# - 1)) - inarg "$1" list_get 2 - }; inarg "$_weight" list_xargs _mw_fn)" + __wei=0 + for i in $(seq 1 $(list_len list)); do + list_get list $i _entry + list_get _entry 2 _vwei + list_get _entry 3 _vlen + __prevwei=$__wei + __wei=$((__wei+(((10000 * _maxll) / _vlen) * _vwei))) + list_set _entry 4 $__wei + done + maxwei=$__wei set -- "" "" "" + _binget() { + list_get "$1" "$2" _binget_ + list_get _binget_ 4 "$3" + } + _bini() ( + t="$1"; v="$2"; + i="${3:-1}"; j="${4:-$(list_len t)}" + bf="$4" + mid=$((i+(j-i)/2)) + _binget t $mid _vmid || return + if { test -z $bf || { _binget t $bf _vbf || return; test \ + "$_vbf" -ge "$_vmid"; }; } && test "$_vmid" -ge "$v" + then + bf=$mid + fi + if test $i = $j; then + echo $bf; test ! -z $bf; return + fi + if test $_vmid -ge $v; then + if test $mid -eq $i; then + echo $bf; test ! -z $bf; return + fi + _bini "$t" $v $i $((mid-1)) $bf + else + if test $mid -eq $j; then + echo $bf; test ! -z $bf; return + fi + _bini "$t" $v $((mid+1)) $j $bf + fi + ) while true; do num=$(randn $maxwei || exit) - line="$(_fn(){ - for arg; do - lnd="$arg" - wei="$(inarg "$arg" list_get 2)" - if [ $num -lt "$wei" ]; then break; fi - done - inarg "$lnd" list_get 1 - }; inarg "$_weight" list_xargs _fn; echo :)" - line="${line%:}" - if { test "$line" != "$3" || test $_len = 1; } && - { test "$line" != "$2" || test $(randn 100) -lt 9; } && - { test "$line" != "$1" || test $(randn 100) -lt 30; } + i=$(_bini "$list" $num) || exit + if { test "$i" != "$3" || test $_len = 1; } && + { test "$i" != "$2" || test $(randn 100) -lt 9; } && + { test "$i" != "$1" || test $(randn 100) -lt 30; } then - printf "%d\n%s\n" "$(printf '%s' "$line" | wc -c)" "$line" || exit - yes '' | tr '\n' ' ' | head -c 65536 # fill pipe quicker + list_get list $i _entry + list_get _entry 1 _name + dd bs=1 count=1 >/dev/null 2>/dev/null || exit + printf "%d\n%s\n" "$(printf '%s' "$_name" | wc -c)" "$_name" || exit + shift 1 + set -- "$@" "$i" fi - shift 1 - set -- "$@" "$line" done -} +) gen2() { gen | while read len; do dd bs=$len count=1 2>/dev/null; printf '\0' @@ -277,10 +279,13 @@ gen2() { } play() { _fifo_playl="$(mktfifo .m3u8)" + _fifo_playctl="$(mktfifo .ctl)" _fifo_script="$(mktfifo .lua)" { cat <<'EOF' local f = assert(io.open("/dev/fd/4")) +local ctl = assert(io.open("/dev/fd/5",'w')) function spawn() + assert(ctl:write('.')) assert(ctl:flush()) local sngi = assert(tonumber(f:read())) local song = f:read(sngi) f:read() @@ -296,30 +301,36 @@ end) spawn() EOF } >"$_fifo_script" & - gen >"$_fifo_playl" & + (gen >"$_fifo_playl" <"$_fifo_playctl") & curpid=$$ clrn(){ rm "$_fifo_playl" rm "$_fifo_script" + rm "$_fifo_playctl" } ( while kill -0 $curpid 2>/dev/null; do sleep 0.05; done; clrn ) & job="$(jobs -p | tail -n1)" { mpv --keep-open --no-video \ --volume=69 --script="$_fifo_script" --idle - } 4<"$_fifo_playl" + } 4<"$_fifo_playl" 5>"$_fifo_playctl" kill $job; clrn } -tell() { _tell_w_f() { for arg; do _name="$(inarg "$arg" list_get 1; echo :)" - _name="${_name%:}"; printf "%s\0" "$_name"; done } - inarg "$list" list_xargs _tell_w_f; } -tell_w() { _tell_w_f() { for arg; do _name="$(inarg "$arg" list_get 2; echo :)" - _name="${_name%:}"; printf "%s\0" "$_name"; done } - inarg "$list" list_xargs _tell_w_f; } -tell_l() { _tell_w_f() { for arg; do _name="$(inarg "$arg" list_get 3; echo :)" - _name="${_name%:}"; printf "%s\0" "$_name"; done } - inarg "$list" list_xargs _tell_w_f; } +for _i in "tell 1" "tell_w 2" "tell_l 3"; do + _inset() { _fn=$1; _j=$2; } + _inset $_i + eval "$( (cat <