Skip to content

Instantly share code, notes, and snippets.

@lezsakdomi
Last active June 20, 2025 16:05
Show Gist options
  • Select an option

  • Save lezsakdomi/027dfa7d45c603e8662af20b5f90b196 to your computer and use it in GitHub Desktop.

Select an option

Save lezsakdomi/027dfa7d45c603e8662af20b5f90b196 to your computer and use it in GitHub Desktop.
Linux Pomodoro timer

pomodoro.sh

A pomodoro timer for Linux-like systems.

Highly inspired by Pomtify

Advantages

  • Stops/pauses music remotely, so it overcomes mobile music playback security limitations
  • By using the Media Player API, not only works with Spotify (for that, check an earlier rev), but also with Tidal
  • Demands user interaction with periodic notifications to confirm that you really finished work/rest

Disadvantages

  • Developing this tool actually decreases my productivity

Requirements

  • bash
  • speech-dispatcher (make sure you also installed espeak-ng and/or festival, and ran spd-conf)
  • A modern Linux desktop with DBus based Media Player API

Features

  • Play/pause music for breaks
  • Say it loud
  • Wait for user interaction after focus/break

Planned features

  • Playing/pausing music using DBus, so that it works with a range of apps (even if you play your music via phone, you can pause there using KDE Connect)
  • Reverse integration: Providing a fake media player, which shows the remain time. Integrates nicely with KDE Connect
#!/bin/bash
#set -e ## a timing application should be somewhat fault tolerant
notify_interval=${notify_interval:-30s}
focus_time=${1:-25m}
break_time=${2:-5m}
initial_break_time=${3:-}
which playerctl >/dev/null || { echo "playerctl not found"; exit 1; }
which spd-say >/dev/null || { echo "spd-say not found, try this command:"; echo "sudo pacman -S speech-dispatcher espeak-ng && spd-say 'Its testing time'"; exit 1; }
remaining_sleep_time() {
ps -o etime= -o args= -p "$1" | perl -MPOSIX -lane '
%map = qw(d 86400 h 3600 m 60 s 1);
$F[0] =~ /(\d+-)?(\d+:)?(\d+):(\d+)/;
$t = -($4+60*($3+60*($2+24*$1)));
for (@F[2..$#F]) {
s/\?//g;
($n, $p) = strtod($_);
$n *= $map{substr($_, -$p)} if $p;
$t += $n
}
$output = "";
for ([60,"%02d"],[60,"%02d:"],[24,"%02d:"],[inf,"%d-"]) {
last unless $t;
$output = sprintf($_->[1], $t % $_->[0]) . $output;
$t = int($t / $_->[0])
}
printf " %s", $output;'
}
end-of(){
msg="$1 time is over, press enter to assert"
playerctl play-pause || echo "Failed to play/pause music"
kdeconnect-cli -d "$(kdeconnect-cli -a 2>/dev/null | cut -d' ' -f3 | head -n1)" --ping-msg "$msg" 2>/dev/null
echo "[$i] $msg"
printf '\7'
time while :; do
spd-say "$msg"
input="$(timeout --foreground ${notify_interval} sh -c 'read line && echo $line')"
code="$?"
if [ "$code" -ne 0 ]; then
continue
else
case "$input" in
+*)
playerctl play-pause
cycle "$1" "$input"
;;
esac
break
fi
done
}
sleep-cdn(){
sleep "$1" & pid="$!"
while test -d /proc/"$pid"/; do
sleep 1
printf '\e[2K'
remaining_sleep_time $pid
printf '\r'
done
}
cycle(){
date
echo "$1 for $2"
sleep-cdn "$2"
end-of "$1"
}
i=0
if [ -n "$initial_break_time" ]; then
cycle Break $initial_break_time
fi
while :; do
let i+=1
cycle Focus $focus_time
cycle Break $break_time
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment