Last active
September 23, 2024 23:38
-
-
Save pabloab/0965faa8d8cff68418e2b6ae1081bd9e to your computer and use it in GitHub Desktop.
Simple pomodoro bash script that switch between sound outputs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Little script to play a music/sound on pomodoros through headphones and call to come back to work through HDMI speakers. | |
# set -euo pipefail # Unofficial bash strict mode | |
# Prerequsitres: gtts (`pip install --user --upgrade gtts`, mpv (`flatpak install io.mpv.Mpv`), vlc, libsox-fmt-mp3 and retry. | |
# Also use yt-dlp instead of yt-dl https://hund.tty1.se/2021/10/12/how-to-use-yt-dlp-instead-of-yt-dl-with-mpv.html | |
# TODO/Known bugs: | |
# - Fix issue with PipeWire: pacmd stat No PulseAudio daemon running, or not running as session daemon. https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/357 | |
# - Use `pw-cli` if PipeWire https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Migrate-PulseAudio#pacmd | |
# - Avoid hiding output by using chronic (from moreutils) | |
# - Add a fadeout befor ending pomodoro | |
# - Add a counter/countdown on stdout | |
# - External sound module lower after midnight (25%, day hours 70%) | |
# - Option to disable audio autoswitch | |
# - Use `retry` also with gtts | |
# - Use set -euo pipefail. May conflict with SC2143 | |
# DONE | |
# - Try to switch to external audio card profile only if exist | |
# - Make interumpible also the break (test) | |
stty -echoctl # hide ^C | |
function finish() { | |
local MSG_EXITING="Exiting..." | |
ps --pid "$pid" &>/dev/null && kill -INT "$pid" | |
echo "$MSG_EXITING" | |
exit 1 | |
} | |
function handle_error() { | |
local MSG_ERRORS="Some errors encountered. Exiting..." | |
echo "$MSG_ERRORS" | |
exit 2 | |
} | |
function handle_error() { | |
local MSG_ERRORS="Some errors encountered. Exiting..." | |
echo "$MSG_ERRORS" | |
exit 2 | |
} | |
trap finish SIGINT | |
# Easily sets the volume of any app | |
function pacmd-set-app-volume() { | |
[[ $(pgrep pipewire) ]] && echo 'You are using PipeWire: This feature is not available.' | |
local player="$1" | |
local volume="$2" | |
local firstPlayerSinkIndex="$(pacmd list-sink-inputs | awk '/index:|application.name |application.process.binary / {print $0};' | grep -iB 1 "$player" | awk '/index:/ {print $2; exit}')" # get specific app sink | |
[[ $firstPlayerSinkIndex ]] && pacmd set-sink-input-volume "$firstPlayerSinkIndex" "$((volume*65536/100))" # 100% → 65536 | |
} | |
function pomodoro() { | |
local LAPSE="25m" | |
local SHORT_BREAK="5m" | |
local LONG_BREAK="15m" | |
local POMODOROS="4" | |
local MPV_RUNTIME_PATH="flatpak run io.mpv.Mpv" | |
local MSG_END_OF_LAST_POMODORO="Fin del pomodoro $POMODOROS" | |
local MSG_END_OF_NORMAL_POMODORO="Fin del pomodoro" | |
local MSG_END_OF_BREAK="Let's go? " | |
local GTTS_LANG="es" | |
local COME_BACK_SOUND="/usr/share/sounds/freedesktop/stereo/complete.oga" | |
local SOUND="music-lofi-girl" # default | |
[[ $(pacmd stat 2>/dev/null) ]] && [[ $(pacmd list-cards | grep "output:hdmi") ]] && local CARDPROFILE_HDMI="output:hdmi-stereo-extra1+input:analog-stereo" | |
local CARDPROFILE_ANALOG="output:analog-stereo+input:analog-stereo" | |
# local CARDPROFILE_BLUETOOTH="output:bluez_sink.14_3F_A6_78_40_ED.a2dp_sink" | |
local GNOME_DNDMODE_PREVIOUS_STATE bold red green reset | |
GNOME_DNDMODE_PREVIOUS_STATE="$(gsettings get org.gnome.desktop.notifications show-banners)" | |
bold=$(tput bold) | |
red=$(tput setaf 1) | |
green=$(tput setaf 2) | |
reset=$(tput sgr0) | |
declare -A music_urls=( | |
["music-freecode"]="https://coderadio-admin.freecodecamp.org/radio/8010/radio.mp3" | |
["music-jazz"]="https://youtu.be/Dx5qFachd3A" | |
["music-lofi"]="https://youtu.be/kgx4WGK0oNU" | |
["music-lofi-girl"]="https://youtu.be/jfKfPfyJRdk" # https://fanlink.to/lofigirl-music ytdl://ytsearch:\"lofi+radio+girl\" | |
["music-coffee"]="https://youtu.be/fEvM-OUbaKs" | |
["music-piano"]="https://youtu.be/xWRHTpqQMGM" | |
["music-synthwave"]="https://youtu.be/oC0iVoNJwbE" | |
["music-spacesynth"]="https://youtu.be/5-anTj1QrWs" | |
["binaural"]="https://youtu.be/F5Tt3LoygCQ" | |
["rain"]="https://youtu.be/q76bMs-NwRk" | |
) | |
# CVLC_OPTIONS="--equalizer-bands "0 0 0 0 0 0 0 0 0 0" --headphone-dim 3 --equalizer-preset classical --equalizer-preamp -15 --compressor-rms-peak 0.5" # {flat,classical,club,dance,fullbass,fullbasstreble,fulltreble,headphones,largehall,live,party,pop,reggae,rock,ska,soft,softrock,techno} | |
[[ $(pgrep pipewire) ]] && echo 'You are using PipeWire: Some features will not be available.' | |
local OPTIND | |
while getopts "p:m:h" options; do | |
case "${options}" in | |
p) POMODOROS=${OPTARG};; | |
m) SOUND=${OPTARG};; | |
h) echo "Options: [-p pomodoros] [-m music-freecode|music-jazz|music-lofi|music-lofi-girl|music-coffee|music-piano|music-synthwave|music-spacesynth|binaural|rain|silence|noise-white|SOUND_FILE_OR_DIR]"; return 0;; | |
*) echo "Error: -${OPTARG} requires an argument."; return 1;; | |
esac | |
done | |
while true; do | |
for i in $(seq 1 "$POMODOROS"); do | |
echo -n "${reset}${bold}${green}Pomodoro $i! ${reset}" | |
[[ $(pacmd stat 2>/dev/null) ]] && pacmd set-card-profile 0 $CARDPROFILE_ANALOG | |
#pactl set-sink-volume "$(pactl list short sinks | grep RUNNING | cut -f1)" 25% | |
pactl set-sink-volume "$(pactl list short sinks | head -n1 | cut -f1)" 30% | |
gsettings set org.gnome.desktop.notifications show-banners false | |
if test -r "$SOUND" -a -f "$SOUND"; then | |
SILENCE_BETWEEN_TRACKS=3 | |
[ -r "$SOUND" ] && timeout --foreground $LAPSE cvlc -q --loop "$SOUND" "vlc://pause:$SILENCE_BETWEEN_TRACKS" &> /dev/null | |
elif test -r "$SOUND" -a -d "$SOUND"; then | |
[ -r "$SOUND" ] && timeout --foreground $LAPSE cvlc -q --loop --random --volume-step 192 --gain 1 "$SOUND" "vlc://pause:$SILENCE_BETWEEN_TRACKS" &> /dev/null | |
else | |
case $SOUND in | |
music-freecode|music-jazz|music-lofi|music-lofi-girl|music-coffee|music-piano|music-synthwave|music-spacesynth|binaural|rain) | |
# timeout --foreground $LAPSE retry --until=success --times=5 --delay=5 -- streamlink --ipv4 --quiet --player="nice -n 19 mpv --no-video" ${music_urls[$SOUND]} "720p,480p,best" # &> /dev/null # |& tee #&> /dev/null | |
timeout $LAPSE retry --until=success --times=3 --delay=3 -- nice -n 19 $MPV_RUNTIME_PATH --no-config --quiet --no-video --ytdl-format=best "${music_urls[$SOUND]}" & # > /dev/null # |& tee | |
pid=$! | |
wait $pid | |
pid_exit_status=$? | |
[[ $pid_exit_status && $pid_exit_status -ne 124 ]] && handle_error # If timeout exit code is different of 0 or 124... | |
;; | |
silence) | |
sleep $LAPSE | |
;; | |
noise-white) | |
[ "m" == ${LAPSE: -1} ] || exit 1 | |
LAPSE=${LAPSE%"m"} | |
play -q -n synth $LAPSE:00 whitenoise | |
;; | |
*) | |
play -q -n synth $LAPSE:00 pinknoise | |
;; | |
esac | |
fi | |
# play -q "/usr/share/sounds/freedesktop/stereo/bell.oga" | |
echo | |
if [ "$POMODOROS" != "$i" ]; then | |
echo "$MSG_END_OF_NORMAL_POMODORO" | gtts-cli - -l "$GTTS_LANG" | play -q -t mp3 - -t alsa |& tee /dev/null # If doesn't work: pip install gtts --upgrade | |
echo "Take a $SHORT_BREAK break" | |
sleep $SHORT_BREAK | |
else | |
echo "$MSG_END_OF_LAST_POMODORO" | gtts-cli - -l "$GTTS_LANG" | play -q -t mp3 - -t alsa |& tee /dev/null # If doesn't work: pip install gtts --upgrade | |
echo "Take a $LONG_BREAK break" | |
sleep $LONG_BREAK | |
fi | |
[[ $(pacmd stat 2>/dev/null) ]] && [[ $CARDPROFILE_HDMI ]] && pacmd set-card-profile 0 $CARDPROFILE_HDMI | |
#pactl set-sink-volume "$(pactl list short sinks | grep RUNNING | cut -f1)" 50% | |
pactl set-sink-volume "$(pactl list short sinks | head -n1 | cut -f1)" 30% | |
gsettings set org.gnome.desktop.notifications show-banners "$GNOME_DNDMODE_PREVIOUS_STATE" | |
echo -n "$MSG_END_OF_BREAK" # The \n is given by the user | |
SECONDS=0 | |
while true; do | |
seq 2 | xargs -I{} play -q $COME_BACK_SOUND -t alsa &> /dev/null # Others: alarm-clock-elapsed.oga dialog-warning.oga message-new-instant.oga phone-incoming-call.oga service-login.oga service-logout.oga suspend-error.oga window-attention.oga | |
# seq 2 | xargs -I{} play -q -n -t alsa synth 2 pl G3 pl B3 pl D4 delay 0 .05 .1 remix - fade 0 1.1 .095 norm -1 | |
# echo "$i" | cw # Morse code. xcwcp qrq cwcp cw | |
local LOOP_TIMEOUT_SECONDS="120" | |
if read -r -t "$LOOP_TIMEOUT_SECONDS"; then | |
#let "minutes=(SECONDS)/60" | |
(( minutes=(SECONDS)/60 )) | |
echo -ne "\033[A\033[${#MSG_END_OF_BREAK}C ${red}You took an extra $minutes'.${reset}\n" | |
break | |
fi | |
done | |
done | |
done | |
echo "Take a longer rest." | |
} | |
pomodoro "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment