You are not logged in.

#1 2023-11-21 11:35:51

dogknowsnx
Member
Registered: 2021-04-12
Posts: 652

[ WAYBAR MODULE v0.7.7 ] RI - Rest your Eyes and Self

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 tongue)

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

HwXv.png
The timeout is user configurable - valid values are 15s to 300s (defaults to 60s)

H3KU.png


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)


RI - Rest your Eyes and Self

"We are eternal, all this pain is an illusion" - Maynard James Keenan

Offline

Board footer

Powered by FluxBB