From 27ae6617ab3650327c696f6763ed5897116f86b5 Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Sat, 1 Mar 2025 16:14:46 -0500 Subject: [PATCH] wip refactor beetag --- beetag | 172 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 88 insertions(+), 84 deletions(-) diff --git a/beetag b/beetag index e786bc1..bd9b98b 100755 --- a/beetag +++ b/beetag @@ -110,6 +110,18 @@ rowir() { fi } +# On slow systems, ~.3 seconds before mpv is ready after starting. This +# impatiently waits. +mpvrpc-wait-idle() { + local -i i + for (( i=0; i<20; i++ )); do + if [[ $(mpvrpco '{ "command": ["get_property", "idle-active"] }' 2>/dev/null | jq .data) == true ]]; then + return + fi + sleep .1 + done + +} mpvrpc-loadfile() { local path nextpath cachedir finalpath nextpath count @@ -183,9 +195,9 @@ mpvrpc-percent-pos() { # # Sets variables: pl_state_path pl_seed_path. Does mkdir of their directory. # -# Creates/recreates $pl_seed_path if needed. +# Creates/recreates file $pl_seed_path if needed. # -# Input vars: random +# Input vars: random, new_random pl-state-init() { local seed_num seed_file pl_state_dir pl_state_file # note: this structure of files is rather haphazard. @@ -207,6 +219,7 @@ pl-state-init() { pl_state_path=$pl_state_dir/$pl_state_file pl_seed_path=$pl_state_dir/$seed_file + readonly pl_state_path pl_seed_path if $new_random || [[ ! -r $pl_seed_path ]]; then { base64 < /dev/urandom | head -c 200 ||:; echo; } > $pl_seed_path @@ -236,7 +249,7 @@ toggle-rare-genres() { button_i[${buttons[i]}]=$i done - } +} # Call from beetag. Queries our songlist and parses it into variables. # @@ -274,7 +287,30 @@ beetag-ls-setup() { ls_lines+=("$ls_line") done - } +} + +# Output most of 1 page worth of playlist entries near the current song. +# +# I only care to see a smallish portion of the list when starting. +# +# Input vars: j, id_count, ls_lines +beetag-head-playlist() { + local head_count head_start ls_line + local -i i + head_count=$(( LINES - 20 )) + head_start=$(( j - head_count / 2 )) + if (( head_start < 0 )); then + head_start=0 + fi + for (( i=head_start; i < head_count && i < id_count; i++ )); do + ls_line="${ls_lines[$i]}" + if (( i == j )); then + echo "* $ls_line" + else + echo "$ls_line" + fi + done +} # tag with beets. # usage: beetag [-r] [-s] QUERY @@ -298,22 +334,43 @@ beetag-ls-setup() { # todo: enter should also unpause beetag() { source /a/bin/ds/beet-data - local last_genre_i tag id char new_item char_i tag remove doplay i j random path - local read_wait line lsout ls_line skip_lookback do_rare_genres pl_state_path - local escape_char escaped_input expected_input skip_input_regex erasable_line seek_sec - local new_random pl_seed_path first_play repeat1 - local -a buttons button_map ids tags tmp_tags ls_lines paths beet_query + + # state vars altered by user input: + local char do_rare_genres last_genre_i doplay=true repeat1=false + local -i volume=70 read_wait=2 j=0 + local -a button_map local -A button_i - local -i i j volume scrolled id_count line_int skip_start pre_j_count head_count skip_lookback - local -i overflow_lines overflow - first_play=true - erasable_line=false - escape_char=$(printf "\u1b") - scrolled=999 # more than any $LINES + # cli options / args + local new_random random + local -a beet_query + + # constants + local escape_char pl_state_path pl_seed_path + local -ar buttons=( {a..p} {r..w} {6..8} , . / - "=") + local -r skip_input_regex="^[0-9]+$" + + # song list vars: + local -a ids ls_lines paths + local -i id_count + + # current song vars: + local id ls_out path + local -a tags + + # boolean state vars + local expected_input remove first_play=true erasable_line=false + + # iterator vars + local ls_line tag + + # misc vars + local char_i escaped_input new_item seek_sec + local -i scrolled=999 # more than any $LINES + local -i i ret line_int skip_start pre_j_count skip_lookback overflow_lines overflow + ### begin arg processing ### random=false - repeat1=false new_random=false case $1 in -r) @@ -336,87 +393,38 @@ beetag() { beet_query=("$@") ### end arg processing ### - readonly -a buttons=( {a..p} {r..w} {6..8} , . / - "=") + escape_char=$(printf "\u1b") + readonly escape_char - ### begin control knob vars ### - volume=70 - doplay=true - ### end control knob vars ### - read_wait=2 toggle-rare-genres pl-state-init beetag-ls-setup - j=0 - if [[ $playlist ]]; then - if [[ -r $pl_state_path ]]; then - j=$(cat $pl_state_path) - fi + if [[ $playlist && -r $pl_state_path ]]; then + j=$(cat $pl_state_path) # playlist position. fi - # i only care to see a smallish portion of the list when starting. - head_count=$(( LINES - 20 )) - head_start=$(( j - head_count / 2 )) - if (( head_start < 0 )); then - head_start=0 - fi - for (( i=head_start; i < head_count && i < id_count; i++ )); do - ls_line="${ls_lines[$i]}" - if (( i == j )); then - echo "* $ls_line" - else - echo "$ls_line" - fi - done - if $doplay; then - #{ mpv --profile=a --volume=$volume --idle 2>&1 & } 2>/dev/null - mpv --profile=a --volume=$volume --idle & - # if we dont sleep, can expect an error like this: - # socat[1103381] E connect(5, AF=1 "/tmp/mpvsock", 14): Connection refused - sleep .1 - fi + beetag-head-playlist + + #{ mpv --profile=a --volume=$volume --idle 2>&1 & } 2>/dev/null # todo: consider using again + mpv --profile=a --volume=$volume --idle & + sleep .1 # or else: socat[1103381] E connect(5, AF=1 "/tmp/mpvsock", 14): Connection refused while true; do id=${ids[j]} path="${paths[$j]}" - lsout="${ls_lines[j]}" - tags=( ${lsout%%,*} ) + ls_out="${ls_lines[j]}" + tags=( ${ls_out%%,*} ) beetag-help - printf "██ %s\n" "$lsout" + printf "██ %s\n" "$ls_out" beetag-nostatus 1 if $doplay; then - # https://stackoverflow.com/a/7687716 - # note: duplicated down below - # - # notes on old method of invoking mpv each time: - # https://superuser.com/questions/305933/preventing-bash-from-displaying-done-when-a-background-command-finishes-execut - # we can't disown or run in a subshell or set +m because all that - # disabled job control from working properly in ways we want. - # todo: figure out some kind of answer to this. I think the solution - # is that we are waiting in 2 second intervals and checking if the - # background job exists. Instead, we should make mpv just idle - # when it is done with a song and then send it a command to play a new track. - #{ mpv --profile=a --volume=$volume "$path" 2>&1 & } 2>/dev/null - # old - #{ beet play "--args=--volume=$volume" "id:$id" 2>&1 & } 2>/dev/null - - # on slow systems, we may need to wait like .3 seconds before mpv - # is ready. so impatiently check until it is ready - if $first_play; then - first_play=false - for (( i=0; i<20; i++ )); do - if [[ $(mpvrpco '{ "command": ["get_property", "idle-active"] }' 2>/dev/null | jq .data) == true ]]; then - mpvrpc-loadfile "$path" - break - fi - sleep .1 - done - else - mpvrpc-loadfile "$path" - fi + if $first_play; then first_play=false; mpvrpc-wait-idle; fi + mpvrpc-loadfile "$path" erasable_line=false fi + while true; do char= if $doplay; then @@ -536,7 +544,6 @@ beetag() { "$escape_char") expected_input=true read -rsn2 escaped_input - skip_input_regex="^[0-9]+$" case $escaped_input in # up char: show all the songs, use less '[A') @@ -632,12 +639,9 @@ beetag() { m beetmq "id:$id" genre=$new_item else remove=false - tmp_tags=() for tag in ${tags[@]}; do if [[ $new_item == "$tag" ]]; then remove=true - else - tmp_tags+=("$tag") fi done if $remove; then -- 2.30.2