-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzen-ambiator.zsh
More file actions
320 lines (282 loc) Β· 10.6 KB
/
Copy pathzen-ambiator.zsh
File metadata and controls
320 lines (282 loc) Β· 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#!/usr/bin/env zsh
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ZEN_AMBIATOR // OS_HUD_V2.1 (zsh Mixer)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Plays and mixes background ambient sounds from your terminal.
# Requires: mpv (for audio playback)
#
# Usage: chmod +x zen-ambiator.zsh && ./zen-ambiator.zsh
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# βββ Check dependency βββ
if ! command -v mpv &>/dev/null; then
printf '\033[31mERROR: mpv not found. Install mpv first:\033[0m\n'
printf ' macOS: brew install mpv\n'
printf ' Linux: apt install mpv | pacman -S mpv\n'
printf ' WSL: sudo apt install mpv\n'
exit 1
fi
# βββ Configuration & Track Library βββ
NOCTUNE="https://raw.githubusercontent.com/karthiknvd/noctune/main/sounds"
SOUNDHELIX="https://www.soundhelix.com/examples/mp3"
# Channel keys (1-9, 1-indexed to match zsh array conventions)
keys=(1 2 3 4 5 6 7 8 9)
# Parallel arrays indexed by key (position 1 = key 1, etc.)
names=(
"Heavy Rain"
"Thunder Storm"
"Train Journey"
"CafΓ© Chatter"
"Lofi Focus"
"Deep Focus Piano"
"Claude FM"
"Lofi Radio Live"
"White Noise"
)
emojis=(
"π§οΈ" "βοΈ" "π" "β" "π§" "πΉ" "π€" "π‘" "π»"
)
# Track URLs β space-separated per channel
tracks_list=(
"$NOCTUNE/rain.mp3 $SOUNDHELIX/SoundHelix-Song-6.mp3 $SOUNDHELIX/SoundHelix-Song-12.mp3 $SOUNDHELIX/SoundHelix-Song-16.mp3 https://stream.zeno.fm/f3t72887vxhvv"
"$NOCTUNE/thunder.mp3 $SOUNDHELIX/SoundHelix-Song-11.mp3 $SOUNDHELIX/SoundHelix-Song-15.mp3 https://stream.zeno.fm/f3t72887vxhvv"
"$NOCTUNE/train.mp3 $SOUNDHELIX/SoundHelix-Song-14.mp3 $SOUNDHELIX/SoundHelix-Song-15.mp3 https://stream.zeno.fm/096t61gh32zuv"
"$SOUNDHELIX/SoundHelix-Song-2.mp3 $SOUNDHELIX/SoundHelix-Song-4.mp3 $SOUNDHELIX/SoundHelix-Song-6.mp3 $SOUNDHELIX/SoundHelix-Song-10.mp3 https://stream.zeno.fm/6szg7vzv32zuv"
"$SOUNDHELIX/SoundHelix-Song-1.mp3 $SOUNDHELIX/SoundHelix-Song-5.mp3 $SOUNDHELIX/SoundHelix-Song-9.mp3 $SOUNDHELIX/SoundHelix-Song-13.mp3 $SOUNDHELIX/SoundHelix-Song-15.mp3 https://streams.fluxfm.de/Chillhop/mp3-128/"
"$SOUNDHELIX/SoundHelix-Song-3.mp3 $SOUNDHELIX/SoundHelix-Song-7.mp3 $SOUNDHELIX/SoundHelix-Song-10.mp3 $SOUNDHELIX/SoundHelix-Song-14.mp3 $SOUNDHELIX/SoundHelix-Song-16.mp3 https://stream.zeno.fm/cg1t3u6h32zuv"
"$SOUNDHELIX/SoundHelix-Song-1.mp3 $SOUNDHELIX/SoundHelix-Song-4.mp3 $SOUNDHELIX/SoundHelix-Song-9.mp3 https://streams.fluxfm.de/Chillhop/mp3-128/"
"https://streams.fluxfm.de/Chillhop/mp3-128/"
"$SOUNDHELIX/SoundHelix-Song-11.mp3 $SOUNDHELIX/SoundHelix-Song-12.mp3"
)
# βββ Player State βββ
typeset -A pids # mpv PID per channel key
typeset -A current_idx # current track index per channel key
typeset -A playing # is channel active?
master_volume=80 # 0-100
# βββ Helpers βββ
get_tracks() {
local key=$1
echo "${tracks_list[$key]}"
}
get_track_count() {
local tracks=(${(s: :)tracks_list[$1]})
echo $#tracks
}
get_current_url() {
local key=$1
local tracks=(${(s: :)tracks_list[$key]})
local idx=${current_idx[$key]:-0}
echo "$tracks[$((idx + 1))]"
}
# βββ Player control functions βββ
start_channel() {
local key=$1
local url=$(get_current_url $key)
local logfile="/tmp/zen-ambiator-$key.log"
# Kill existing process if any
stop_channel $key
mpv --no-video --volume=$master_volume --really-quiet --no-terminal \
"$url" &>/dev/null &
pids[$key]=$!
playing[$key]="yes"
}
stop_channel() {
local key=$1
if [[ -n "${pids[$key]}" ]] && kill -0 "${pids[$key]}" 2>/dev/null; then
kill "${pids[$key]}" 2>/dev/null
wait "${pids[$key]}" 2>/dev/null
fi
pids[$key]=""
playing[$key]="no"
}
stop_all() {
for key in $keys; do
stop_channel $key
done
}
restart_channel() {
local key=$1
if [[ "${playing[$key]}" == "yes" ]]; then
stop_channel $key
start_channel $key
fi
}
# βββ Skip track βββ
skip_track() {
local key=$1
local tracks=(${(s: :)tracks_list[$key]})
local count=$#tracks
# Single-track channels can't skip
if (( count <= 1 )); then
# Restart current stream
restart_channel $key
return
fi
local idx=${current_idx[$key]:-0}
idx=$(( (idx + 1) % count ))
current_idx[$key]=$idx
if [[ "${playing[$key]}" == "yes" ]]; then
stop_channel $key
start_channel $key
fi
}
# βββ Toggle Play/Pause βββ
toggle_play() {
local key=$1
if [[ "${playing[$key]}" == "yes" ]]; then
stop_channel $key
else
start_channel $key
fi
}
# βββ Master Volume βββ
change_master_volume() {
local val=$1
# Clamp 0-100
if (( val < 0 )); then val=0; fi
if (( val > 100 )); then val=100; fi
master_volume=$val
# Restart all active channels with new volume
for key in $keys; do
if [[ "${playing[$key]}" == "yes" ]]; then
stop_channel $key
start_channel $key
fi
done
}
# βββ Info text for display βββ
get_info_text() {
local key=$1
local tracks=(${(s: :)tracks_list[$key]})
local count=$#tracks
local idx=${current_idx[$key]:-0}
# Key 8 = Lofi Radio Live (single stream)
if [[ "$key" == "8" ]]; then
printf "SYS_LINK // 24/7_STREAM "
elif (( idx == count - 1 )); then
printf "SYS_LINK // 24/7_RADIO_LIVE"
else
local tn=$((idx + 1))
local tt=$((count - 1))
printf "TRACK_LINK // SYS_%02d_%02d " "$tn" "$tt"
fi
}
# βββ ANSI Colors βββ
NC="\033[0m"
CYAN="\033[36m"
MAGENTA="\033[35m"
PURPLE="\033[34m"
DARKCYAN="\033[36m"
YELLOW="\033[33m"
WHITE="\033[37m"
GRAY="\033[90m"
RED="\033[31m"
GREEN="\033[32m"
BOLD="\033[1m"
# βββ Cleanup handler βββ
cleanup() {
printf "\n${CYAN}Shutting down all channels...${NC}\n"
stop_all
exit 0
}
trap cleanup SIGINT SIGTERM EXIT
# βββ Display βββ
draw_interface() {
# ANSI clear screen and home cursor
printf "\033[2J\033[H"
# Header
printf "${CYAN} ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}\n"
printf "${CYAN} _____ ______ _ _ __ __ _____ _ _ _____ ${NC}\n"
printf "${CYAN} |__ / | ____| \ | | /\ |\/| | \/ |_ _\ \ / | ___|${NC}\n"
printf "${MAGENTA} / / | |__ | \| | / \ | | | \ / | | | \ \/ /| |__ ${NC}\n"
printf "${MAGENTA} / /_ | __| | . \` | / /\ \ | | | |\/| | | | \ / | __| ${NC}\n"
printf "${PURPLE} /____| |____|_|\_\_|/_/ \_| | |_| |_|_____| \/ |____| ${NC}\n"
printf "${CYAN} ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}\n"
printf "${DARKCYAN} SYS_LINK // OS_HUD_V2.1 MASTER_GAIN // ${master_volume}%${NC}\n"
printf "${CYAN} ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}\n"
# Categories
local nature=(1)
local weather=(2)
local cozy=(3 4)
local music=(5 6 7 8 9)
_draw_category "πΏ Nature" $nature
_draw_category "β‘ Weather" $weather
_draw_category "π₯ Cozy" $cozy
_draw_category "π΅ Music" $music
# Footer
printf "${CYAN} ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}\n"
printf "${WHITE} COMMANDS: [Num] Toggle Play | s [Num] Skip | mv [Val] Master${NC}\n"
printf "${WHITE} m Mute All | q Quit${NC}\n"
printf "${CYAN} ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}\n"
}
_draw_category() {
local header=$1; shift
local -a cat_keys=($@)
printf " ${YELLOW}[ // $header ]${NC}\n"
for key in $cat_keys; do
local name="${names[$key]}"
local emoji="${emojis[$key]}"
local status="${playing[$key]}"
local info=$(get_info_text $key)
if [[ "$status" == "yes" ]]; then
printf " ${WHITE}[%2s]${NC} ${WHITE}%s${NC} ${WHITE}%-18s${NC} " "$key" "$emoji" "$name"
printf "${DARKCYAN}%s${NC} " "$info"
printf "${GREEN}[ACTIVE]${NC}\n"
else
printf " ${WHITE}[%2s]${NC} %s %-18s " "$key" "$emoji" "$name"
printf "${DARKCYAN}%s${NC} " "$info"
printf "${GRAY}[MUTED]${NC}\n"
fi
done
printf "\n"
}
# βββ Initialize βββ
printf "${CYAN}Initializing ZEN AMBIATOR...${NC}\n"
for key in $keys; do
current_idx[$key]=0
playing[$key]="no"
pids[$key]=""
done
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# βββ Main Loop βββ
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
while true; do
draw_interface
# Read command
printf " ENTER COMMAND "
read -r input
# Parse
local parts=(${(s: :)input})
local cmd="${parts[1]}"
case "$cmd" in
q|exit)
printf "${RED}Shutting down...${NC}\n"
stop_all
break
;;
m)
stop_all
;;
mv)
if (( $#parts >= 2 )); then
local val="${parts[2]}"
if [[ "$val" =~ ^[0-9]+$ ]]; then
change_master_volume $val
fi
fi
;;
s)
if (( $#parts >= 2 )); then
local target="${parts[2]}"
if (( target >= 1 && target <= 9 )); then
skip_track $target
fi
fi
;;
[1-9])
toggle_play $cmd
;;
*)
# Unknown command β just redraw
;;
esac
done