more beets stuff
authorIan Kelling <ian@iankelling.org>
Sun, 26 Feb 2023 20:06:40 +0000 (15:06 -0500)
committerIan Kelling <ian@iankelling.org>
Sun, 26 Feb 2023 20:06:40 +0000 (15:06 -0500)
brc2
subdir_files/.config/mpv/mpv.conf
subdir_files/.local/share/konsole/profileian.profile

diff --git a/brc2 b/brc2
index 12586845d49bad0468673dd5d041ae5463830367..f23de9b53b7195ff0f5f84eb8095b32dbfe26396 100644 (file)
--- a/brc2
+++ b/brc2
@@ -525,7 +525,15 @@ EOF
 
 # beet playlist. use beetag with a playlist name
 bpl() {
-  eval beetag -r "$@" "${bpla[${@: -1}]}"
+  local playlist playlist_regex
+  playlist="${*: -1}"
+  playlist_regex='[a-z0-9_]'
+  if [[ ! $playlist =~ $playlist_regex ]]; then
+    echo "bpl: error unexpected chars in playlist: $playlist"
+    return 1
+  fi
+  # all but last arg as options
+  eval beetag -r "${*:1:$# - 1}" "${bpla[$playlist]}"
 }
 complete -W "${!bpla[*]}" bpl
 
@@ -538,31 +546,101 @@ beetmq() {
   sed 's/^format_item:.*/format_item: ignore_this/' ~/.config/beets/config.yaml >$tmpf
   beet -c $tmpf modify -y "$@" > >(grep -vFx -e 'ignore_this' -e 'Modifying 1 items.' ||:)
   rm "$tmpf"
-  scrolled+=1
+  beetag-nostatus 1
+}
+
+kill-bg-quiet() {
+  # https://stackoverflow.com/a/5722874
+  kill %% 2>/dev/null ||:; wait %% 2>/dev/null ||:
+}
+
+# debug variables
+dv() {
+  for arg; do
+    printf "%s=%s " "$arg" "${!arg}"
+  done
+  echo
 }
 
 # Must be called from beetag for variables to be setup
 beetag-help() {
+  local -i i j col_total row col button_total row_total remainder_cols remainder_term
+  col_total=4
+  button_total=${#button_map[@]}
+  row_total=$(( button_total / col_total ))
+  remainder_cols=$(( button_total % col_total ))
+  # for debugging
+  #dv button_total row_total remainder_cols
+  beetag-nostatus
   #   - 3 is just a constant that helps things work in practice.
   if [[ $LINES ]] && (( LINES - 3 < scrolled )); then
     hr
-    for (( i=0; i<${#button_map[@]}; i++)); do
-      if (( i % 3 == 2 )); then
-        printf "%s %s\n" ${buttons[i]} ${button_map[i]}
+    for (( i=0; i<button_total; i++)); do
+      row=$(( i / col_total ))
+      col=$(( i % col_total ))
+      remainder_term=$remainder_cols
+      if (( col < remainder_term )); then
+        remainder_term=$col
+      fi
+      j=$(( col * row_total + row + remainder_term ))
+      # avoid double newline when we have exactly row * col buttons
+      if (( i == button_total - 1 )); then
+        printf "%s %s" ${buttons[j]} ${button_map[j]}
+      elif (( i % col_total == col_total -1 )); then
+        printf "%s %s\n" ${buttons[j]} ${button_map[j]}
       else
-        printf "%s %-15s" ${buttons[i]} ${button_map[i]}
+        printf "%s %-15s" ${buttons[j]} ${button_map[j]}
       fi
     done
-    echo
     cat <<'EOF'
-y other genres   z fg player      ' = toggle play
-; previous       _ = delete       -/+ volume   ->/<- skip
+
+
+y other genres   z fg player      ' = toggle play  1-5 rate
+; previous       _ = delete       up/down skip     mpv vol,pause,seek
 EOF
     hr
     scrolled=10
   fi
 }
 
+# Must be called from beetag for variables to be setup
+beetag-nostatus() {
+  if (( $# )); then
+    scrolled=$(( scrolled + $1 ))
+  fi
+  if $erasable_line; then
+    # https://stackoverflow.com/a/71286261
+    printf '\033[1A\033[K'
+  fi
+  erasable_line=false
+}
+# meant to be called from beetag
+beetag-status() {
+  if $erasable_line; then
+    # https://stackoverflow.com/a/71286261
+    printf '\033[1A\033[K'
+  fi
+  erasable_line=true
+}
+
+# meant to be called from beetag
+mpvrpc() {
+  if jobs -p | grep -q . &>/dev/null; then
+    printf "%s\n" "$*" | socat - /tmp/mpvsock >/dev/null ||:
+  fi
+}
+# meant to be called from beetag
+# o for get output
+mpvrpco() {
+  # note: testing for background jobs will output nothing if we are in a pipeline
+  printf "%s\n" "$*" | socat - /tmp/mpvsock ||:
+}
+
+# meant to be called from beetag
+mpvrpc-percent-pos() {
+  mpvrpco '{ "command": ["get_property", "percent-pos"] }' | jq .data | sed 's/\..*/%/' 2>/dev/null ||:
+}
+
 # tag with beets.
 # usage: beetag [-r] [-s] QUERY
 # it lists the query, reads an input char for tagging one by one.
@@ -582,19 +660,22 @@ EOF
 # q quit
 # ret next
 beetag() {
-  local last_genre_i fstring tag id char new_item char_i genre tag remove doplay i j random
+  local last_genre_i fstring tag id char new_item char_i genre tag remove doplay i j random path
   local do_rare_genres read_wait help line lsout tmp ls_line skip_lookback
-  local escape_char escaped_input expected_input skip_input_regex
-  local -a pl_tags buttons button_map ids tags rare_genres tmp_tags initial_ls ls_lines
+  local escape_char escaped_input expected_input skip_input_regex right_pad erasable_line seek_sec
+  local pl_state_path pl_state_dir pl_state_file
+  local new_random pl_seed_path seed_num seed_file
+  local -a pl_tags buttons button_map ids tags tmp_tags initial_ls ls_lines paths
   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
 
-
+  erasable_line=false
   escape_char=$(printf "\u1b")
   scrolled=999 # more than any $LINES
   ### begin arg processing ###
   random=false
+  new_random=false
   case $1 in
     -r)
       random=true
@@ -604,6 +685,10 @@ beetag() {
       random=false
       shift
       ;;
+    -x)
+      new_random=true
+      shift
+      ;;
   esac
   if (( ! $# )); then
     echo beetag: error expected a query arg >&2
@@ -617,17 +702,9 @@ beetag() {
   volume=70
   read_wait=2
   doplay=true
-  # because we were destined to run out of single key buttons.
-  rare_genres=(
-    jazz
-    musical
-    noise
-    skit
-    spoken-w
-  )
 
   last_genre_i=$(( ${#common_genres[@]} - 1 ))
-  buttons=( {a..p} {r..w} 0 {6..9} , . / )
+  buttons=( {a..p} {r..w} {6..8} , . / - "=")
   button_map=(${common_genres[@]} ${pl_tags[@]})
   fstring=
   for tag in "${pl_tags[@]}"; do
@@ -638,37 +715,94 @@ beetag() {
     button_i[${buttons[i]}]=$i
   done
 
-  # TODO: use shuf --random-source=FILE to save the random sort order
-  # for reusing later, so we can pickup where we left off in a playlist.
+  # note: this structure of files is rather haphazard.
+  seed_num=1 # later we might want a few
+  seed_file=seed$seed_num
+  if $random; then
+    pl_state_file=$seed_num
+  else
+    pl_state_file=sorted
+  fi
+  pl_state_dir=/i/info/pl-state
+  if [[ $playlist ]]; then
+    pl_state_dir=$pl_state_dir/nopl
+  else
+    pl_state_dir=$pl_state_dir/$playlist
+  fi
+  pl_state_path=$pl_state_dir/$pl_state_file
+  pl_seed_path=$pl_state_dir/$seed_file
 
+
+  if $new_random || [[ ! -r $pl_seed_path ]]; then
+    mkdir -p $pl_state_dir
+    { base64 < /dev/urandom | head -c 200 ||:; echo; } > $pl_seed_path
+  fi
+
+
+
+  # PijokVipiotOzeph is just a random string for a delimiter
   # shellcheck disable=SC2016 # obvious reason
-  mapfile -t initial_ls < <(beet ls -f '%ifdef{rating,$rating }'"$fstring"'$genre | $artist - $album - $title   $length  $id' "$@" | { if $random; then sort -R; else cat; fi; } )
-  j=0
-  # i only care to see the head of the list.
-  head_count=$(( LINES - 20 ))
+  mapfile -t initial_ls < <(beet ls -f '%ifdef{rating,$rating }'"$fstring"'$genre | $artist - $album - $title   $length  $id PijokVipiotOzeph $path' "$@" | { if $random; then sort -R --random-source=$pl_seed_path; else cat; fi; } )
+  id_count=${#initial_ls[@]}
   for line in "${initial_ls[@]}"; do
-    id="${line##* }"
+    path="${line#*PijokVipiotOzeph }"
+    # https://github.com/koalaman/shellcheck/issues/2171
+    # shellcheck disable=SC2190 # bug in shellcheck, looking at paths from an earlier function
+    paths+=("$path")
+    line_no_path="${line% PijokVipiotOzeph*}"
+    id="${line_no_path##* }"
     ids+=("$id")
-    right_pad="${line%% |*}"
-    ls_line="$(printf %-11s "$right_pad")${line#$right_pad}"
+    right_pad="${line_no_path%% |*}"
+    ls_line="$(printf %-11s "$right_pad")${line_no_path#"$right_pad"}"
     ls_lines+=("$ls_line")
-    if (( j < head_count )); then
+    i=$(( i+1 ))
+  done
+
+
+
+
+  j=0
+  if [[ $playlist ]]; then
+    if [[ -r $pl_state_path ]]; then
+      j=$(cat $pl_state_path)
+    fi
+  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
-    j=$(( j+1 ))
   done
-  id_count=${#ids[@]}
-  for (( j=0; j < id_count; j++ )); do
+
+  while true; do
     id=${ids[j]}
+    path="${paths[$j]}"
     lsout="${ls_lines[j]}"
     tags=( ${lsout%%,*} )
     beetag-help
     printf "██ %s\n" "$lsout"
-    scrolled+=1
+    beetag-nostatus 1
     if $doplay; then
       # https://stackoverflow.com/a/7687716
       # note: duplicated down below
-      { beet play "--args=--volume=$volume" "id:$id" 2>&1 & } 2>/dev/null
+      # 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
+      erasable_line=false
     fi
     while true; do
       char=
@@ -679,7 +813,7 @@ beetag() {
         # Automatically skip to the next song if this one ends, unless
         # we turn off the autoplay.
         if (( ret == 142 )) || [[ ! $char ]]; then
-          if bg %% &>/dev/null; then
+          if jobs -p | grep -q . &>/dev/null; then
             continue
           else
             break
@@ -691,12 +825,12 @@ beetag() {
       beetag-help
       if [[ $char == $'\n' ]]; then
         # https://stackoverflow.com/a/5722874
-        kill %%; wait %% 2>/dev/null ||:
+        kill-bg-quiet
         break
       fi
       case $char in
         ";")
-          kill %%; wait %% 2>/dev/null ||:
+          kill-bg-quiet
           j=$(( j - 2 ))
           break
           ;;
@@ -706,44 +840,46 @@ beetag() {
             doplay=false
           else
             doplay=true
-            kill %%; wait %% 2>/dev/null ||:
-            { beet play "--args=--volume=$volume" "id:$id" 2>&1 & } 2>/dev/null
+            kill-bg-quiet
+            { mpv --profile=a --volume=$volume "$path" 2>&1 & } 2>/dev/null
+            #{ beet play "--args=--volume=$volume" "id:$id" 2>&1 & } 2>/dev/null
+            erasable_line=false
           fi
-          scrolled+=1
+          beetag-nostatus 1
           continue
           ;;
         _)
-          kill %%; wait %% 2>/dev/null ||:
+          kill-bg-quiet
           m beet rm --delete --force "id:$id"
-          scrolled+=4 # guessing. dont want to test atm
+          beetag-nostatus 4 # guessing. dont want to test atm
           break
           ;;
         [1-5])
           beetmq "id:$id" rating=$char
           continue
           ;;
-        -)
+        9)
           volume=$(( volume - 5 ))
           if (( volume < 0 )); then
             volume=0
           fi
-          echo volume=$volume
-          scrolled+=1
-          continue
-          ;;
-        q)
-          kill %%; wait %% 2>/dev/null ||:
-          return
-          ;;
-        +)
+          ;;&
+        0)
           volume+=5
           if (( volume > 130 )); then
             volume=130
           fi
+          ;;&
+        0|9)
+          mpvrpc '{ "command": ["set_property", "volume", '$volume'] }'
+          beetag-status
           echo volume=$volume
-          scrolled+=1
           continue
           ;;
+        q)
+          kill-bg-quiet
+          return
+          ;;
         y)
           if $do_rare_genres; then
             do_rare_genres=false
@@ -764,7 +900,7 @@ beetag() {
           continue
           ;;
         z)
-          scrolled+=3
+          beetag-nostatus 3
           # if we ctrl-z, it will put the whole function into sleep. so
           # basically, we can't return from a foregrounded mpv like we
           # would like to without some strange mechanism I can't think
@@ -776,17 +912,35 @@ beetag() {
           fi
           continue
           ;;
+
+        #
+        " ")
+          # output time if we aren't already paused
+          if [[ $(mpvrpco '{ "command": ["get_property", "pause"] }' | jq .data) == false ]]; then
+            # minutes/seconds
+            #date -d @"$(mpvrpco '{ "command": ["get_property", "playback-time"] }' | jq .data)" +%M:%S ||:
+            beetag-status
+            mpvrpc-percent-pos
+          fi
+          # originally found this solution, which worked fine.
+          #kill -STOP %% &>/dev/null
+          #
+          mpvrpc '{ "command": ["cycle", "pause"] }'
+          continue
+          ;;
         "$escape_char")
           expected_input=true
           read -rsn2 escaped_input
           skip_input_regex="^[0-9]+$"
           case $escaped_input in
-            '[D')
-              skip_lookback=5
+            # up char
+            '[A')
               skip_start=0
+              skip_lookback=5
               if (( j - skip_lookback > skip_start )); then
                 skip_start=$(( j - skip_lookback ))
               fi
+              beetag-nostatus $(( id_count - skip_start - 1 ))
               {
                 line_int=0
                 for (( i=skip_start; i < id_count; i++ )); do
@@ -798,18 +952,20 @@ beetag() {
                   line_int+=1
                 done
               } | less -F
-              scrolled+=$(( id_count - skip_start - 1 ))
               ;;
-            '[C')
+            # down char
+            '[B')
               # skip forward, but show the last few songs anyways.
               skip_start=0
               skip_lookback=3
               if (( j - skip_lookback > skip_start )); then
                 skip_start=$(( j - skip_lookback ))
               fi
+              beetag-nostatus $(( id_count - skip_start - 1 ))
+
               line_int=0
               overflow_lines=$LINES
-              for (( i=skip_start; i < overflow_lines - 1; i++ )); do
+              for (( i=skip_start; i < overflow_lines - 1 && i < id_count; i++ )); do
                 ls_line="${ls_lines[i]}"
                 overflow=$(( ${#ls_line} / ( COLUMNS - 1 ) ))
                 overflow_lines=$(( overflow_lines - overflow ))
@@ -820,7 +976,21 @@ beetag() {
                 echo "$line_int | $ls_line"
                 line_int+=1
               done
-              scrolled+=$(( id_count - skip_start - 1 ))
+              ;;
+            # left key
+            '[D')
+              seek_sec=-8
+              ;;&
+            # right key
+            '[C')
+              seek_sec=8
+              ;;&
+            '[C'|'[D')
+              beetag-status
+              mpvrpc-percent-pos
+              erasable_line=true
+              mpvrpc '{ "command": ["seek", "'$seek_sec'"] }'
+              continue
               ;;
             *)
               expected_input=false
@@ -828,9 +998,9 @@ beetag() {
           esac
           if $expected_input; then
             read -r skip_input
-            case skip_input in
+            case $skip_input in
               q)
-                kill %%; wait %% 2>/dev/null ||:
+                kill-bg-quiet
                 return
                 ;;
             esac
@@ -841,7 +1011,7 @@ beetag() {
                 j=$(( j - 1 ))
               fi
             fi
-            kill %%; wait %% 2>/dev/null ||:
+            kill-bg-quiet
             break
           fi
           ;;
@@ -873,6 +1043,14 @@ beetag() {
         fi
       fi
     done
+    if (( j < id_count - 1 )); then
+      j+=1
+    else
+      j=0
+    fi
+    if [[ $playlist ]]; then
+      echo $j >$pl_state_path
+    fi
   done
 }
 
index 8ad1916fcf7ede062e6dc33c38f060cc3b90a491..56023b770142812c1f2f274274bd2e7b4f532f27 100644 (file)
@@ -36,4 +36,10 @@ display-tags=
 #
 # Found via man mpv and its suggestion to use
 # --msg-level=all=trace
+#
+# for supressing
+# "Audio device underrun detected." it requires all=error.
+
 msg-level=cplayer=warn,ffmpeg/demuxer=error
+
+input-ipc-server=/tmp/mpvsock
index 747c3b6b2b39ac506993ebfb98c0b05b69f8a0d3..ed3f64bfeddb2d532d0c76d5cfddc30678704eb1 100644 (file)
@@ -1,5 +1,5 @@
 [Appearance]
-ColorScheme=BlackOnWhite
+ColorScheme=Linux
 Font=DejaVu Sans Mono,12,-1,5,50,0,0,0,0,0
 
 [General]