Skip to content

Added scrolling text to Mac player module and cleaned up functions #356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,13 @@ set -g @dracula-mac-player-remote-back "R"
set -g @dracula-mac-player-remote-next "N"
```

To add a scrolling effect to the player instead of a truncated text:

```bash
set -g @dracula-mac-player-scroll true
set -g @dracula-mac-player-scroll-speed 0.08 # Lower speeds means faster scroll between renders
```

### mpc - [up](#table-of-contents)

This widget displays music information provided by mpc.
Expand Down Expand Up @@ -681,6 +688,14 @@ Set the playerctl metadata format like so:
set -g @dracula-playerctl-format "► {{ artist }} - {{ title }}"
```

To set the player to scroll the text:

```bash
set -g @dracula-playerctl-scroll true # on by default
set -g @dracula-playerctl-width 25
set -g @dracula-playerctl-speed 0.08 # Small speeds = faster scrolling
```

### ram-usage - [up](#table-of-contents)

This widget displays the currently used ram as GB per GB.
Expand Down
42 changes: 35 additions & 7 deletions scripts/mac-player.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
export LC_ALL=en_US.UTF-8

current_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$current_dir/utils.sh"

source $current_dir/utils.sh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Quote the sourced path to avoid breakage on paths containing spaces
Unquoted expansions break if the script is located in a directory with whitespace (e.g. “/Users/al ice/tmux”). Always quote path-like variables when sourcing or executing.

-source $current_dir/utils.sh
+source "$current_dir/utils.sh"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
source $current_dir/utils.sh
source "$current_dir/utils.sh"
🤖 Prompt for AI Agents
In scripts/mac-player.sh at line 6, the sourced path variable $current_dir is
not quoted, which can cause the script to break if the directory path contains
spaces. Fix this by enclosing $current_dir/utils.sh in double quotes when using
source, like source "$current_dir/utils.sh", to ensure the path is correctly
interpreted even with spaces.


function trackStatus() {
local active_player
Expand Down Expand Up @@ -185,6 +184,25 @@ function remoteControl() {
fi
}

# Scroll the text
function scroll() {
local str=$1
local width=$2
local speed=$3

local scrolling_text=""
local i=0
local len=${#str}

for ((i = 0; i <= len; i++)); do
scrolling_text=$(slice_text "$str" "$i" "$width")
printf "\r%s " "$scrolling_text"

sleep "$speed"
done

printf "\r%s " "$scrolling_text"
}

Comment on lines +187 to 206
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

scroll() blocks for len*speed seconds and resets every run – consider a time-based slice instead
The current loop:

  • Sleeps len times, so a 60-char title at 0.08s stalls the script for almost 5 s – longer than the default refresh rate and likely to spawn overlapping processes.
  • Restarts from index 0 on every invocation, causing a “jump” rather than seamless scroll.
  • Uses <= len; when i == len the slice starts at the terminating NUL, returning an empty string.

A safer, non-blocking alternative is to compute the start index from the current epoch modulo len, output one slice, and let tmux refresh drive the animation:

-function scroll() {
-  local str=$1
-  local width=$2
-  local speed=$3
-
-  local len=${#str}
-  for ((i = 0; i < len; i++)); do
-    printf "\r%s " "$(slice_text "$str" "$i" "$width")"
-    sleep "$speed"
-  done
-}
+scroll() {
+  local str=$1   width=$2   speed=$3
+  local len=${#str}
+
+  # Calculate frame based on time so the function prints *once* per call.
+  local frame=$(( $(date +%s%N) / $(printf '1%0.s' {1..${#speed}}) % len ))
+  echo "$(slice_text "$str" "$frame" "$width")"
+}

This keeps runtime ~ 1 ms, eliminates overlap and yields smooth, continuous scrolling.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In scripts/mac-player.sh around lines 187 to 206, the scroll() function blocks
execution for len*speed seconds and restarts the scroll from index 0 each time,
causing jumps and potential overlapping processes. To fix this, refactor
scroll() to compute the start index based on the current epoch time modulo the
string length, output only one slice per call, and remove the loop and sleep
calls. This change will make scrolling non-blocking, smooth, and continuous,
relying on external refresh timing to drive the animation.

main() {
# save buffer to prevent lag
Expand All @@ -206,7 +224,9 @@ main() {
BACK_BUTTON=$(get_tmux_option "@dracula-mac-player-remote-back" "R")
NEXT_BUTTON=$(get_tmux_option "@dracula-mac-player-remote-next" "N")


# Scroll
SCROLL=$(get_tmux_option "@dracula-mac-player-scroll" false)
SCROLL_SPEED=$(get_tmux_option "@dracula-mac-player-scroll-speed" 0.08)

# os checker
if [[ "$OSTYPE" != "darwin"* ]]; then
Expand All @@ -217,15 +237,23 @@ main() {
# Remote Access
if [[ "$REMOTE_ACCESS" == true ]]; then
remoteControl "$PLAY_PAUSE_BUTTON" "$BACK_BUTTON" "$NEXT_BUTTON" "$REMOTE_APP"

fi

if [ ! -f "$cache_file" ] || [ $(($(date +%s) - $(stat -f%c "$cache_file"))) -ge "$RATE" ]; then
trackStatus "$PAUSE_ICON" "$PLAY_ICON" > "$cache_file"
sliceTrack "$(cat $cache_file)" "$MAX_LENGTH" > "$cache_file"
trackStatus "$PAUSE_ICON" "$PLAY_ICON" >"$cache_file"

if [ "$SCROLL" = false ]; then
sliceTrack "$(cat $cache_file)" "$MAX_LENGTH" >"$cache_file"
fi
fi

cat "$cache_file"
# Allow scrolling
local str=$(cat "$cache_file")
if [ "$SCROLL" = true ] && [ "${#str}" -ge $MAX_LENGTH ]; then
scroll "$str" "$MAX_LENGTH" "$SCROLL_SPEED"
else
echo "$str"
fi
}

main
Expand Down
53 changes: 28 additions & 25 deletions scripts/playerctl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,30 @@ export LC_ALL=en_US.UTF-8
current_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source $current_dir/utils.sh

function slice_loop() {
local str="$1"
local start="$2"
local how_many="$3"
# Set the configuration

# Scroll the text
# arg1: text
# arg2: width
# arg3: speed
scroll() {
local str=$1
local width=$2
local speed=$3

local scrolling_text=""
local i=0
local len=${#str}

local result=""
for ((i = 0; i <= len; i++)); do
scrolling_text=$(slice_text "$str" "$i" "$width")

for ((i = 0; i < how_many; i++)); do
local index=$(((start + i) % len))
local char="${str:index:1}"
result="$result$char"
printf "\r%s " "$scrolling_text"

sleep "$speed"
done

echo "$result"
printf "\r%s " "$scrolling_text"
}

main() {
Expand All @@ -31,12 +40,13 @@ main() {
fi

FORMAT=$(get_tmux_option "@dracula-playerctl-format" "Now playing: {{ artist }} - {{ album }} - {{ title }}")
SCROLL=$(get_tmux_option "@dracula-playerctl-scroll" true)
WIDTH=$(get_tmux_option "@dracula-playerctl-width" 25)
SPEED=$(get_tmux_option "@dracula-playerctl-speed" 0.08)

playerctl_playback=$(playerctl metadata --format "${FORMAT}")
playerctl_playback="${playerctl_playback} "

# Adjust width of string
terminal_width=25

# Initial start point for scrolling
start=0
len=${#playerctl_playback}
Expand All @@ -50,18 +60,11 @@ main() {

scrolling_text=""

for ((start = 0; start <= len; start++)); do
scrolling_text=$(slice_loop "$playerctl_playback" "$start" "$terminal_width")
echo -ne "\r"
echo "$scrolling_text "
echo -ne "\r"

sleep 0.08
done

echo -ne "\r"
echo "$scrolling_text "
echo -ne "\r"
if [ "$SCROLL" = true ]; then
scroll "$playerctl_playback" "$WIDTH" "$SPEED"
else
echo "$playerctl_playback"
fi
}

# run the main driver
Expand Down
29 changes: 29 additions & 0 deletions scripts/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,32 @@ normalize_percent_len() {
printf "%${left_spaces}s%s%${right_spaces}s\n" "" $1 ""
}

# Create a slice of the text to show currently in the module
# arg1: The full string
# arg2: Where to start the loop from
# arg3: The length of characters to display
slice_text() {
local str="$1"
local start="$2"
local how_many="$3"

# Check that the string is not empty
if [[ -z $str ]]; then
echo ""
return 0
fi

local len=${#str}

local result=""
# Capture the strings to show
for ((i = 0; i < how_many; i++)); do
local index=$(((start + i) % len))
local char="${str:index:1}"

# Append the character to show
result="$result$char"
done

echo "$result"
}