fix longstanding bug with skip back. yay
authorIan Kelling <ian@iankelling.org>
Sat, 1 Mar 2025 22:59:46 +0000 (17:59 -0500)
committerIan Kelling <ian@iankelling.org>
Sat, 1 Mar 2025 22:59:46 +0000 (17:59 -0500)
beetag

diff --git a/beetag b/beetag
index bd9b98b9cf7cbf8c4800747ae7655c577aca910c..56ad3b4ec61d724a9a84d4866bf3011f2d3da6ba 100755 (executable)
--- a/beetag
+++ b/beetag
@@ -59,7 +59,7 @@ beetag-help() {
 
 
 y other genres   z fg player      ' = toggle play  1-5 rate    ] repeat1
-; previous       _ = delete       up/down skip     mpv vol,pause,seek
+; previous       _ delete         j/k skip         mpv_keys vol,pause,seek
 EOF
     hr
     scrolled=10
@@ -312,6 +312,41 @@ beetag-head-playlist() {
   done
 }
 
+beetag-advance-maybe() {
+  if ! $repeat1; then
+    j=$(( ( j + 1 ) % id_count ))
+  fi
+}
+
+# Input vars: j, skip_start
+#
+# Output vars: j, got_track
+beetag-track-select() {
+  local skip_input
+  local -i new_j
+  local -r skip_input_regex="^[0-9]+$"
+  read -r skip_input
+  got_track=true
+  if [[ ! $skip_input =~ $skip_input_regex ]]; then
+    got_track=false
+    # maybe we changed our mind, so just ignore it.
+    return
+  fi
+
+  # example:
+  # 0   skip_start=5
+  # 1
+  #   * j=7
+  # 2
+  # 3
+
+  new_j=$(( skip_start + skip_input ))
+  if (( new_j >= j )); then
+    new_j+=1
+  fi
+  j=$new_j
+}
+
 # tag with beets.
 # usage: beetag [-r] [-s] QUERY
 # it lists the query, reads an input char for tagging one by one.
@@ -320,7 +355,7 @@ beetag-head-playlist() {
 # by immediately jumping forward into the song. this is set in the beets
 # config yaml.
 #
-# (available buttons: ` ) ] [ and non-printing chars, see
+# (available buttons: ` ) ] [ and non-printing chars, see
 # https://stackoverflow.com/questions/10679188/casing-arrow-keys-in-bash
 #
 #
@@ -347,8 +382,7 @@ beetag()  {
 
   # 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]+$"
+  local -ar buttons=( {a..i} {l..p} {r..w} {6..8} , . / - "=" '\' )
 
   # song list vars:
   local -a ids ls_lines paths
@@ -359,7 +393,7 @@ beetag()  {
   local -a tags
 
   # boolean state vars
-  local expected_input remove first_play=true erasable_line=false
+  local expected_input remove got_track first_play=true erasable_line=false
 
   # iterator vars
   local ls_line tag
@@ -423,6 +457,9 @@ beetag()  {
       if $first_play; then first_play=false; mpvrpc-wait-idle; fi
       mpvrpc-loadfile "$path"
       erasable_line=false
+      if [[ $playlist ]]; then
+        echo $j >$pl_state_path
+      fi
     fi
 
     while true; do
@@ -438,6 +475,7 @@ beetag()  {
               [[ $(mpvrpco '{ "command": ["get_property", "idle-active"] }' | jq .data) == false ]]; then
             continue
           else
+            beetag-advance-maybe
             break
           fi
         fi
@@ -446,11 +484,16 @@ beetag()  {
       fi
       beetag-help
       if [[ $char == $'\n' ]]; then
+        beetag-advance-maybe
         break
       fi
       case $char in
         ";")
-          j=$(( j - 2 ))
+          if (( j == 0 )); then
+            j=$(( id_count - 1 ))
+          else
+            j=$(( j - 1 ))
+          fi
           break
           ;;
         "'")
@@ -468,6 +511,7 @@ beetag()  {
         _)
           m beet rm --delete --force "id:$id"
           beetag-nostatus 4 # guessing. dont want to test atm
+          j=$(( ( j + 1 ) % id_count ))
           break
           ;;
         [1-5])
@@ -501,6 +545,57 @@ beetag()  {
           echo repeat1=$repeat1
           continue
           ;;
+        j)
+          # 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 < id_count; i++ )); do
+            ls_line="${ls_lines[i]}"
+            overflow=$(( ${#ls_line} / ( COLUMNS - 1 ) ))
+            overflow_lines=$(( overflow_lines - overflow ))
+            if (( i == j )); then
+              echo "  * $ls_line"
+              continue
+            fi
+            echo "$line_int | $ls_line"
+            line_int+=1
+          done
+          beetag-track-select
+          if $got_track; then
+            break
+          else
+            continue
+          fi
+          ;;
+        k)
+          # skip back. show all the songs, use less
+          skip_start=0
+          beetag-nostatus $(( id_count - skip_start - 1 ))
+          {
+            line_int=0
+            for (( i=skip_start; i < id_count; i++ )); do
+              if (( i == j )); then
+                echo "  * ${ls_lines[i]}"
+                continue
+              fi
+              echo "$line_int | ${ls_lines[i]}"
+              line_int+=1
+            done
+          } | less -F
+          beetag-track-select
+          if $got_track; then
+            break
+          else
+            continue
+          fi
+          ;;
         q)
           kill-bg-quiet
           return
@@ -545,52 +640,7 @@ beetag()  {
           expected_input=true
           read -rsn2 escaped_input
           case $escaped_input in
-            # up char: show all the songs, use less
-            '[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
-                  if (( i == j )); then
-                    echo "  * ${ls_lines[i]}"
-                    continue
-                  fi
-                  echo "$line_int | ${ls_lines[i]}"
-                  line_int+=1
-                done
-              } | less -F
-              ;;
-            # down char
-            '[B')
-              echo ok >>/tmp/x
-
-              # 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 < id_count; i++ )); do
-                ls_line="${ls_lines[i]}"
-                overflow=$(( ${#ls_line} / ( COLUMNS - 1 ) ))
-                overflow_lines=$(( overflow_lines - overflow ))
-                if (( i == j )); then
-                  echo "  * $ls_line"
-                  continue
-                fi
-                echo "$line_int | $ls_line"
-                line_int+=1
-              done
-              ;;
+            # it was buggy to differentiate between up and down, '[A' and '[B'
             # left key
             '[D')
               seek_sec=-8
@@ -610,23 +660,6 @@ beetag()  {
               expected_input=false
               ;;
           esac
-          if $expected_input; then
-            read -r skip_input
-            case $skip_input in
-              q)
-                kill-bg-quiet
-                return
-                ;;
-            esac
-            if [[ $skip_input =~ $skip_input_regex ]]; then
-              pre_j_count=$(( j - skip_start ))
-              j=$(( j + skip_input - pre_j_count ))
-              if (( skip_input < pre_j_count )); then
-                j=$(( j - 1 ))
-              fi
-            fi
-            break
-          fi
           ;;
       esac
       char_i=${button_i[$char]}
@@ -653,15 +686,5 @@ beetag()  {
         fi
       fi
     done
-    if ! $repeat1; then
-      if (( j < id_count - 1 )); then
-        j+=1
-      else
-        j=0
-      fi
-    fi
-    if [[ $playlist ]]; then
-      echo $j >$pl_state_path
-    fi
   done
 }