You are not logged in.
If you're the kind that wants to take regular breaks but you need a little nudge in order to do so, this might be for you.
This module is a very lightweight alternative to - and inspired by - SafeEyes. It will remind you to take a break every 20min by default (adjust "interval" inside the module to your liking). There will be a 10s queue during which you can pause a video etc. or opt out of the scheduled break by right-clicking on the icon - but there is a twist...
# Scope/Features:
Break reminder (using 'bemenu')
Notifications (acoustical - 10s before a break and at the end of a break; optional 'fyi' or 'libnotify').
Basic options (ships a config file; requires 'jq')
Skip breaks (no strict mode available)
Rewards (simple count of breaks taken consecutively - will be reduced to '1' by cheating as well as skipping on right-click)
Basic statistics (optional)
Simplicity
# Dependencies: 'bemenu', 'jq', 'fyi'/'libnotify' (optional - for notifications)
- This module has been tested successfully on other (non-systemd) Linux distros -
NOTE: If you're running a different distro, make sure to also have 'paplay' or 'aplay' executables installed - the module defaults to 'paplay' (which comes with 'libpulse' as a waybar dependency on Arch) - so you may want to adjust 'ri.sh' manually.
# Installation:
Please place script files (*.sh) inside '~/.local/bin/' and utility files inside '~/.local/share/',
and don't forget to make the scripts executable. Make sure to add the module to your waybar config.
Once everything is set up, you can test the module by running '~/.local/bin/ri.sh' from the terminal.
ri.sh:
#!/bin/bash
#
#[v0.7.7]
#
# This script depends on 'bemenu' 'jq'
pidof bemenu >/dev/null 2>&1 && pkill -x bemenu
class="enabled" # don't move [10]
RIN=/tmp/riNHB
TMR=/tmp/riTMR
LCS=~/.local/share
CFG=${LCS}/ri.conf
RIT=${LCS}/ri.txt
tmo_cfg=$(jq -r .timeout_sec ${CFG})
idl_cfg=$(jq -r .idle_sec ${CFG})
snd_q_cfg=$(jq -r .sound_queue ${CFG})
snd_e_cfg=$(jq -r .sound_end ${CFG})
prs_cfg=$(jq -r .prompt_string ${CFG})
psr_cfg=$(jq -r .persist_reboot ${CFG})
sts_cfg=$(jq -r .keep_stats ${CFG})
trp_cfg=$(jq -r .transparent ${CFG})
lns_cfg=$(jq -r .lines ${CFG})
if [[ -f ${CFG} ]]
then
if [[ "${tmo_cfg}" -lt 15 ]] || [[ "${tmo_cfg}" -gt 300 ]]
then
tmo_cfg=60
fi
if [[ "${psr_cfg}" = "yes" ]]
then
RIB=~/.cache/riBRK
else
RIB=/tmp/riBRK
rm -f ~/.cache/riBRK
fi
if [[ "${sts_cfg}" = "yes" ]]
then
RIH=~/.cache/riHST
touch ${RIH}
else
rm -f ~/.cache/riHST
fi
else
tmo_cfg=60
RIB=/tmp/riBRK
rm -f ~/.cache/riBRK
rm -f ~/.cache/riHST
fi
[[ -f ${RIB} ]] || date '+%H:%M' > ${RIB}
_brk() {
lst_brk=$(tail -n 1 ${RIB})
cnt_brk=$(cat ${RIB} | wc -l)
}
_brk
if [[ "${class}" = "enabled" ]]
then
menu="<span color='#555555'>Right-click: skip\nOn click: off</span> <span color='#00CF52'>[on]</span>"
else
menu="<span color='#555555'>Right-click: skip\nOn click: on</span> <span color='#D7005F'>[off]</span>"
fi
_prt() {
printf '%s\n' "{\"class\":\"$class\",\"tooltip\":\
\"Timeout: ${tmo_cfg}s\nRewards: $cnt_brk @$lst_brk\n$menu\"}"
rm -f ${TMR}
touch ${RIB}
}
trap _prt EXIT
[[ -s ${RIN} ]] && exit
pgrep -f rinhibit >/dev/null 2>&1 && exit
[[ "$(( $(date +"%s") - $(stat -c "%Y" "/proc/$(pidof -s waybar)") ))" -lt 10 ]] && exit
if [[ "$(( $(date +"%s") - $(stat -c "%Y" "${RIB}") ))" -gt ${idl_cfg} ]]
then
date '+%H:%M' >> ${RIB}
[[ -f ${RIH} ]] && date >> ${RIH}
_brk
exit
fi
_tmr() {
while pidof bemenu >/dev/null 2>&1
do
echo "1" >> ${TMR} ; sleep 1
done
}
if [[ -f ${CFG} ]] && [[ "${trp_cfg}" = "yes" ]]
then
_bmn() {
timeout ${tmo_cfg} bemenu -l "${lns_cfg}" -n -s -w --cw 1 -C --prompt="${prs_cfg} " \
--fn 'monospace 15' --fixed-height --monitor=all --cf \#00000000 \
--nf \#999999 --af \#999999 --hf \#00CF52 --tf \#999999 \
--nb \#000000E6 --hb \#000000E6 --sb \#000000E6 \
--ab \#000000E6 --fb \#000000E6 --tb \#000000E6 &
}
else
_bmn() {
timeout ${tmo_cfg} bemenu -l "${lns_cfg}" -n -s -w --cw 1 -C --prompt="${prs_cfg}" \
--fn 'monospace 15' --fixed-height --monitor=all --cf \#00000000 \
--tf \#999999 --nf \#999999 --af \#999999 --hf \#00CF52 &
}
fi
if [[ "${class}" = "enabled" ]]
then
paplay ${LCS}/${snd_q_cfg} &
# Alternatively (requires 'alsa-utils'):
#aplay -q --file-type=wav ${LCS}/${snd_q_cfg} &
# Popup (requires 'fyi' or 'libnotify'):
if type fyi >/dev/null 2>&1
then
fyi -t 10000 -u low "RI" "10...9...8..."
elif type notify-send >/dev/null 2>&1
then
! type fyi >/dev/null 2>&1 &&
notify-send -t 10000 -u low "RI" "10...9...8..."
fi
sleep 10
if [[ ! -s ${RIN} ]]
then
if [[ -f ${RIT} ]]
then
shuf -n 1 ${RIT} | _bmn > /dev/null
_tmr
else
echo "Rest your eyes..." | _bmn > /dev/null
_tmr
fi
TMT=$(( ${tmo_cfg} - 5 ))
if [[ "$(cat ${TMR} | wc -l)" -lt ${TMT} ]]
then
echo "$(tail -n 1 ${RIB})" > ${RIB}
else
date '+%H:%M' >> ${RIB}
[[ -f ${RIH} ]] && date >> ${RIH}
fi
_brk
paplay ${LCS}/${snd_e_cfg}
# Alternatively (requires 'alsa-utils'):
#aplay -q --file-type=wav ${LCS}/${snd_e_cfg}
fi
fi
# Source code: "https://bbs.archlinux.org/viewtopic.php?id=290491"
module (NOTE: if you're running 'qtile', please use the second module):
"custom/ri": {
"format": "",
// "format": "<span size='large'></span>",
"interval": 1200, // NOTE: '"idle_sec": "<sec>"' in your 'ri.conf' has to be higher, e.g. '"idle_sec": "2400"' !
"return-type":"json",
"exec": "sleep 0.1 && ~/.local/bin/ri.sh",
"on-click": "~/.local/bin/ri_swt.sh",
"on-click-right": "~/.local/bin/ri_skp.sh",
"tooltip": true
},
module (qtile):
"custom/ri": {
"format": "",
// "format": "<span size='large'></span>",
"interval": 1200, // NOTE: '"idle_sec": "<sec>"' in your 'ri.conf' has to be higher, e.g. '"idle_sec": "2400"' !
"return-type":"json",
"exec": "sleep 0.4 && ~/.local/bin/ri.sh",
"on-click": "sleep 0.3 && ~/.local/bin/ri_swt.sh",
"on-click-right": "~/.local/bin/ri_skp.sh",
"tooltip": true
},
ri_swt.sh:
#!/bin/bash
RIN=/tmp/riNHB
RIS=~/.local/bin/ri.sh
if grep 'class="enabled"' ${RIS} >/dev/null 2>&1
then
sed -i "10s/class=.*\ #/class=\"disabled\"\ #/" ${RIS}
else
sed -i "10s/class=.*\ #/class=\"enabled\"\ #/" ${RIS}
fi
echo "skip" > ${RIN} && sleep 1 && : > ${RIN}
# Source code: "https://bbs.archlinux.org/viewtopic.php?id=290491"
ri_skp.sh:
#!/bin/bash
RIN=/tmp/riNHB
CFG=~/.local/share/ri.conf
psr_cfg=$(jq -r .persist_reboot ${CFG})
if [[ -f ${CFG} ]]
then
if [[ "${psr_cfg}" = "yes" ]]
then
RIB=~/.cache/riBRK
else
RIB=/tmp/riBRK
rm -f ~/.cache/riBRK
fi
else
RIB=/tmp/riBRK
rm -f ~/.cache/riBRK
fi
echo "$(tail -n 1 ${RIB})" > ${RIB}
echo "skip" > ${RIN} && sleep 15 && : > ${RIN}
# Source code: "https://bbs.archlinux.org/viewtopic.php?id=290491"
style:
#custom-ri.enabled {
color: #00CF52;
}
#custom-ri.disabled {
color: #555555;
}
# Utility files
ri.conf:
{
"timeout_sec": "60",
"idle_sec": "18000",
"sound_queue": "Hummingbird.wav",
"sound_end": "A-Tone.wav",
"prompt_string": "BREATHE!",
"persist_reboot": "no",
"keep_stats": "no",
"transparent": "yes",
"lines": "50"
}
NOTE: If 'bemenu' doesn't show up (depending on your hw/compositor combo), you may want to play with the "lines" option, e.g. decrease the number until 'bemenu' shows up).
The default sound files (wav) can be downloaded from:
https://soundbible.com/1815-A-Tone.html
https://soundbible.com/940-Hummingbird.html (though I think they recorded a swallow, not a hummingbird )
Please rename and copy them to '~/.local/share/', or use/copy different files and set them in the config, respectively.
ri.txt (example - list of newline separated messages to be shown randomly during breaks):
Rest your eyes...
Everything is OK...
Enjoy the silence...
Let's do some eye gymnastics...
For more info on how to add the module to waybar, please consult:
https://github.com/Alexays/Waybar
# Statistics (optional)
If enabled, RI will store a basic statistics database (>=v0.7.6) which can be fuzzy-searched by e.g. utilizing the already installed 'bemenu', or by simply feeding it into 'fzf' inside the terminal:
ri_hst.sh (bemenu):
#!/bin/bash
CFG=~/.local/share/ri.conf
sts_cfg=$(jq -r .keep_stats ${CFG})
if [[ -f ${CFG} ]]
then
if [[ "${sts_cfg}" = "yes" ]]
then
RIH=~/.cache/riHST
else
exit 1
fi
fi
_bmn() {
bemenu --prompt="[RI] Break History: " \
--fn 'monospace 10' -i -l 40 -n -w -W 0.3 \
--cw 1 --cf \#555555 --nf \#999999 --hf \#6FB790 \
--tf \#999999 --nb \#000000E6 --hb \#000000E6 \
--fb \#00000000 --tb \#000000E6 --ab \#000000E6
}
[[ -f ${RIH} ]] && _bmn < ${RIH} > /dev/null
# Source code: "https://bbs.archlinux.org/viewtopic.php?id=290491"
'fzf' example (consider adding an alias to your shell's rc file):
fzf --cycle --exact --multi --reverse --no-separator --prompt "[RI] Break History: " --info inline-right < ~/.cache/riHST
# WIP (workaround for systemd - skip if using 'acpid')
In order to automatically skip breaks on resume from suspend, create the service file below and enable it by issuing (replace 'username' with your actual user):
# systemctl enable resume@username
/etc/systemd/system/resume@.service:
[Unit]
Description=User resume actions
After=suspend.target
[Service]
User=%I
Type=simple
ExecStart=/bin/sh -c 'exec -a rinhibit sleep 3' &
[Install]
WantedBy=suspend.target
If you are already using that service, simply append the 'ExecStart' command above (<your commands> ; <new command>)
For more info, please see: https://wiki.archlinux.org/title/Power_ … vice_files
Correspondingly, use the command below whenever you want to inhibit the module (e.g. in theming scripts using symlinks to different 'style.css' files where 'waybar' needs to be reloaded):
sh -c 'exec -a rinhibit sleep 3' &
This will spawn a simple 3 second sleep process renamed to "rinhibit", which gets picked up by the module.
# Screenshots
The timeout is user configurable - valid values are 15s to 300s (defaults to 60s)
ri_upd.sh (script that checks for updates of this module - make sure to bump the version number found at the top of 'ri.sh' in order for this to work. Basically do the update according to the changelog..):
#!/bin/bash
RI="RI-module"
UTD="up-to-date"
UPD="Update"
SCR=~/.local/bin/ri.sh
URL=https://bbs.archlinux.org/viewtopic.php?id=290491
BLUE='\e[1;34m'
GREEN='\e[1;36m'
NOCOLOR='\e[0m'
_grp() {
grep $(curl -s "$1" | head -n 6 | awk '/MODULE/ { print $4 }') "$2" >/dev/null 2>&1
}
_nsd() {
type notify-send >/dev/null 2>&1 &&
notify-send -t 5000 "$@"
}
ping -4 -n -c 1 archlinux.org >/dev/null 2>&1 || exit 2
echo
if [[ -f ${SCR} ]]
then
if _grp ${URL} ${SCR}
then
printf "${RI}: ${BLUE}${UTD}${NOCOLOR}\n"
_nsd "${RI}" "${UTD}" --urgency=low
else
printf "${RI}: ${GREEN}${UPD}${NOCOLOR}: \"${URL}\"\n"
_nsd "${RI}" "${UPD} available"
fi
else
printf "${RI}: module not installed (properly) - please see:\n\n \"${URL}\"\n"
fi
echo
Last edited (2024-11-19 15:47)
Additional links:
https://github.com/Cloudef/bemenu
Other "humane tech" recommendations:
https://gitlab.com/chinstrap/gammastep / https://sr.ht/~kennylevinsen/wlsunset
https://github.com/darkreader/darkreader
CHANGELOG: 'Initial beta release 'v0.1.b'; forgot to add 'style' - *oops*; #ri.sh: implement inhibit on first start; bump version to 'v0.2.b'; #ri.conf: added option for transparency; #ri.sh: made necessary changes; bump version to 'v0.3.b'; #ri.conf: increase default timeout to 60s; #ri.sh: made necessary changes; 'bmn()': added '--monitor=all' switch; #ri.conf: added option for setting number of lines (height adjustment); #ri.sh: made necessary changes; bump version to 'v0.4.b'; #ri.sh: rewards will now be revoked by cheating, as well; bump version to 'v0.5.b': #ri.conf: added option to make rewards persistent upon reboot; #ri_skp.sh: made necessary changes: #ri.sh: made necessary changes; bump version to 'v0.6.b'; #ri.sh: small optimization; bump version to 'v0.7.b'; #ri.sh: "tooltip": new layout; play queue sound in background; bump version to 'v0.7.0'; #ri.conf: added option for setting an idle period (Explanation: If there hasn't been any activity for the given period of time, this period will be considered as a break taken, and the next scheduled break will be skipped - the value must be higher than the interval between breaks set in the module - it's effectively disabled by default by setting it to 5 hours); #ri.sh: made necessary changes; bump version to 'v0.7.1'; #ri.sh: "tooltip": be more concise; bump version to 'v0.7.2'; #ri.sh: 'bmn()': added '-C' switch (disable all cursor events); fix: rewards being reset after idle period; bump version to 'v0.7.3'; #module: click response times can actually be sped up; #ri.sh: check for 'notify-send' executable (libnotify-ready); bump version to 'v0.7.4'; #ri.sh: fix: idle mode getting triggered by disabling the module; bump version to 'v0.7.5'; #ri.conf: added option for building a basic statistics database (see alse "Statistics" above for additional tools); #ri.sh: made necessary changes; minor adjustments; bump version to 'v0.7.6'; 'fzf': added '--exact' flag; #module: added note regarding idle management; #ri.sh: 'bemenu': adapt to upstream theming changes; small improvements; bump version to 'v0.7.7'; *.sh: small improvements; #ri.sh: check for 'fyi' executable (fyi-ready)'
Last edited by dogknowsnx (2024-11-19 15:49:30)
Offline