lots: shellcheck, streaming stuff, fixes
[distro-setup] / myi3status
1 #!/bin/bash
2 # Copyright (C) 2019 Ian Kelling
3 # SPDX-License-Identifier: AGPL-3.0-or-later
4
5 # usage:
6 #
7 # * left click seconds to reset & enable main timer which shows 30
8 # minutes in blue and half hours in orange.
9 #
10 # * right click seconds to disable minutes & half hours of main timer
11 #
12 # * left click minutes to reset & enable 2nd timer.
13 #
14 # * right click minutes to disable 2nd timer
15
16 # docs:
17 #
18 # Sections from right to left.
19 #
20 # section #1, labeled day_percent
21 #
22 # 1. Thousandths of a 16 hour day left. 1 = 57.6 seconds.
23 # 2. Bar of one thousand of a day which gets shorter by ninths. One ninth is 6.4 seconds.
24 # 3. Start of the day (only the non-zero numbers). Set this with the ds command.
25 # 4. The time right now.
26 # 5. Ten thousands of the year left. 1 = 52:34 minutes (leap year = 52:42)
27 # 6. Bar of 1/10,000 of a year shrinking by ninths. 1 ninth = 5:50 minutes (leap year = 5:51 mins).
28 #
29 # section #2, labeled seconds
30 #
31 # block characters, ▉, are added every 3 seconds, a total of 20 for 1
32 # minute. The groups of 5 blocks = 15 seconds each.
33 #
34 # section #3, labeled mins
35 #
36 # Only enabled by clicking on seconds, see usage.
37 #
38 # Block characters are added every minute until 30, then reset. There
39 # are 6 groups of 5 minutes.
40 #
41 # Section #4
42 #
43 # Half hours in orange, grouped into groups of 2. This will grow until
44 # it fills the screen.
45 #
46 # Section #5 & 6
47 #
48 # Only enabled by clicking on mins section, see usage.
49 #
50 # These repeat sections 3 and 4 in violet and some other color.
51 #
52 #
53 if [ -z "$BASH_VERSION" ]; then echo "error: shell is not bash" >&2; exit 1; fi
54
55 source /a/bin/bash-bear-trap/bash-bear
56
57 shopt -s nullglob
58 shopt -s dotglob
59
60 tmp_focus1=$(mktemp)
61 tmp_focus2=$(mktemp)
62
63 mins=0
64 half_hours=0
65 start=$EPOCHSECONDS
66 domins=false
67
68 if date -d 'february 29' &>/dev/null; then
69 days_in_this_year=366
70 else
71 days_in_this_year=365
72 fi
73
74
75 get_daystart() {
76 if [[ /b/data/daystart -ot /b/data/daystart-generated && $day_start_24h ]]; then
77 return 0
78 fi
79 day_start_24h=$(cat /b/data/daystart)
80 day_start_sig_digits=${day_start_24h%?}
81 day_start_sig_digits=${day_start_sig_digits%0}
82 day_start_hour=${day_start_24h%??}
83 day_start_min=${day_start_24h: -2}
84 echo $day_start_hour > /b/data/daystart-generated
85 echo $day_start_min >> /b/data/daystart-generated
86 day_start=$(date -d $day_start_hour:$day_start_min +%s)
87 # for after midnight but before the day start.
88 if (( day_start > EPOCHSECONDS )); then
89 day_start=$(date -d "$day_start_hour:$day_start_min yesterday" +%s)
90 fi
91 }
92
93
94 main() {
95 get_daystart
96
97 ## debug
98 # if [[ $line ]]; then
99 # echo "line=$line" >>/tmp/t
100 # fi
101 case $line in
102 ""|"[") : ;;
103 *)
104 json="${line#,}"
105 case $(echo "$json" | jq -r .name) in
106 seconds)
107 case $(echo "$json" | jq -r .button) in
108 # left click
109 1)
110 start=$EPOCHSECONDS
111 domins=true
112 ;;
113 # right click
114 3)
115 domins=false
116 ;;
117 esac
118 ;;
119 mins)
120 case $(echo "$json" | jq -r .button) in
121 1)
122 start2=$EPOCHSECONDS
123 ;;
124 3)
125 start2=
126 ;;
127 esac
128
129 ;;
130 esac
131 esac
132
133 time=$((EPOCHSECONDS - start))
134 total_mins=$(( time / 60 ))
135 mins=$(( total_mins % 30 ))
136 half_hours=$(( total_mins / 30 ))
137
138
139
140 printf '['
141
142 if [[ -e /dev/shm/iank-status && ! -e /tmp/quiet-status ]]; then
143 ps_char=
144 eval "$(< /dev/shm/iank-status)"
145 fi
146
147 touch --date="10 minutes ago" $tmp_focus1
148 touch --date="30 minutes ago" $tmp_focus2
149 f=/tmp/focus-last-input
150
151 # We output a reminder to do input to the focus app if we haven't done
152 # it less 10 minutes ago (but dont bother if its been more than 30
153 # minutes, maybe we aren't running it anymore.)
154 if [[ -e $f && $tmp_focus2 -ot $f && $tmp_focus1 -nt $f ]]; then
155 ps_char="=======FOCUS====== $ps_char"
156 fi
157
158 if [[ -e /tmp/iank-i3-no-auto ]]; then
159 ps_char="$ps_char I"
160 fi
161 if [[ -e /tmp/no-obs-auto-scene-switch ]]; then
162 ps_char="$ps_char O"
163 fi
164
165
166 printf '{ "name":"status", "color":"#ED297D", "full_text": "%s' "$ps_char"
167 printf '"},'
168
169
170 if [[ $start2 ]]; then
171 time2=$((EPOCHSECONDS - start2))
172 total_mins2=$(( time2 / 60 ))
173 mins2=$(( total_mins2 % 30 ))
174 half_hours2=$(( total_mins2 / 30 ))
175 # this is duplicate of mins and half hours except for different
176 # colors and looking at vars above.
177
178 # begin half hours
179 printf '{ "color": "#EFC93E", "full_text": "'
180 for ((i=half_hours2-1; i >= 0 ; i--)); do
181 printf
182 if (( i > 0 && i % 2 == 0 )); then
183 printf " "
184 fi
185 done
186 printf '"},'
187
188
189 # begin minutes
190 printf '{ "name":"mins2", "color":"#ED297D", "full_text": "'
191 for ((i=29; i >= 0 ; i--)); do
192 if (( i < mins2 )); then
193 printf
194 else
195 printf " "
196 fi
197 if (( i > 0 && i % 5 == 0 )); then
198 printf " "
199 fi
200 done
201 printf '"},'
202
203 fi
204
205 if $domins; then
206 # begin half hours
207 printf '{ "color": "#FFB542", "full_text": "'
208 for ((i=half_hours-1; i >= 0 ; i--)); do
209 printf
210 if (( i > 0 && i % 2 == 0 )); then
211 printf " "
212 fi
213 done
214 printf '"},'
215
216
217 # begin minutes
218 printf '{ "name":"mins", "color":"#0D6BDD", "full_text": "'
219 for ((i=29; i >= 0 ; i--)); do
220 if (( i < mins )); then
221 printf
222 else
223 printf " "
224 fi
225 if (( i > 0 && i % 5 == 0 )); then
226 printf " "
227 fi
228 done
229 printf '"},'
230 fi
231
232 # begin seconds
233 printf '{ "name": "seconds", "full_text": "'
234
235 for ((i=0; i < 20; i++)); do
236 # This first condition is to make the transition from full to empty
237 # be less jarring. We are filling a bucket of space with ticks of
238 # time, we would have to choose to show full or empty, but never
239 # both. Or we could have a half/tick to show full then empty real
240 # quick. I decided to try having it work like a snake, empty out the
241 # 1st quarter as we fill up the last quarter.
242
243 if (( i > 0 && i % 5 == 0 )); then
244 printf " "
245 fi
246 i_end=$(( time % 60 / 3 + 1 ))
247 if (( i_end - i > 15 )); then
248 printf " "
249 elif (( i_end == 1 && i == 0 )); then
250 printf B
251 elif (( i < i_end )); then
252 printf
253 else
254 printf " "
255 fi
256 done
257 printf '"},'
258
259 ## begin day percent, in thousandths, plus a spark block for ten_thousandth.
260 printf '{ "name": "day_percent", "full_text": "'
261
262
263 # after 24 hours, reset the day start
264 if (( day_start + 24 * 60 * 60 < EPOCHSECONDS )); then
265 day_start=$(date -d $day_start_hour:$day_start_min +%s)
266 fi
267
268 # there are 9 spark levels, 1/9 = .111.... In order to keep it in bash math, we upscale
269 # the number and divide by 111, 3 digits is good enough accuracy.
270 spark_index="$(( (1000000 -(EPOCHSECONDS - day_start)*1000000 / (16*60*60) ) % 1000 / 111 ))"
271 spark=" ▁▂▃▄▅▆▇█"
272 # note: 960 minutes, so 10 minutes is about 1%
273 day_thousandth=$(( 1000 - (EPOCHSECONDS - day_start)*1000 / (16*60*60) ))
274 printf %s "$day_thousandth${spark:spark_index:1}$day_start_sig_digits $(date "+%l:%M")"
275
276 # .1% of a waking year is ~5.75 hours, or 365 thousandths of a day.
277 # 1% of a waking year is 3.7 days
278 # A spark line of a thousandth of a waking year is 39 minutes.
279 year_start=$(date +%s -d 'january 1 6am')
280 year_days=$(( (EPOCHSECONDS - year_start) / (24*60*60) ))
281 year_start=$(( year_start + year_days * 8*60*60 ))
282 year_spark_index=$(( ( 1000000 - (EPOCHSECONDS - year_start)*1000000 / (days_in_this_year*16*60*60) ) % 1000 / 111 ))
283 year_tenthousandth=$(( 10000 - (EPOCHSECONDS - year_start)*10000 / (days_in_this_year*16*60*60) ))
284 printf %s " $year_tenthousandth${spark:year_spark_index:1}"
285
286
287 echo '"}
288 ],
289 '
290 }
291
292
293 # pass any arg and we just run once. mainly for debugging
294 if (( $# )); then
295 main
296
297 # debug
298 #echo date -d $day_start_hour:$day_start_min +%s
299 #echo day_start=$day_start now=$EPOCHSECONDS
300
301 else
302 printf '{ "version": 1, "click_events": true }\n['
303 while true; do
304 if [[ -e /tmp/noi3bar ]]; then
305 sleep 10
306 else
307 main
308 line=
309 read -r -t 3 line ||:
310 fi
311 done
312 fi
313
314 rm -f $tmp_focus1 $tmp_focus2