Last active
March 30, 2022 13:23
-
-
Save ewen-lbh/488afb3f7f4c1393f563228a8ebbf758 to your computer and use it in GitHub Desktop.
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 python3 | |
# TODO overall completion % instead of single-countdown. | |
""" | |
Usage: | |
pomodoro [SESSIONS] [CYCLES] [WORK] [BREAK] [PAUSE] | |
pomodoro --total-cycles=TOTAL_CYCLES --sessions-of=CYCLES | |
Arguments: | |
SESSIONS Number of sessions (cycles then pause) [default: 9999] | |
CYCLES Number of cycles (work then break) per session: [default: 4] | |
WORK Duration of a work period (in minutes) [default: 25] | |
BREAK Duration of a break period (in minutes) [default: 5] | |
PAUSE Duration of a pause period (in minutes) [default: 20] | |
Options: | |
--total-cycles=TOTAL_CYCLES Specifies a total number of cycles to do. | |
Will be split into (n//m) sessions of m cycles and one session of (n%m) cycles, | |
where n = --total-cycles and m = --sessions-of | |
--sessions-of=CYCLES See --total-cycles. | |
""" | |
from docopt import docopt | |
from time import sleep | |
from subprocess import run | |
from pathlib import Path | |
class StateFile: | |
def __init__(self, filepath: Path): | |
filepath.parent.mkdir(parents=True, exist_ok=True) | |
filepath.write_text("") | |
self.filepath = filepath | |
self.cycle = "" | |
self.cycle_number = 0 | |
self.total_cycles = 0 | |
self._total_time = 0 | |
self.done = 0 | |
@property | |
def total_time(self): | |
return self._total_time | |
@total_time.setter | |
def total_time(self, val): | |
self._total_time = val | |
self.done = 0 | |
@property | |
def remaining(self): | |
return max([self.total_time - self.done, 0]) | |
@property | |
def percentbar(self): | |
return f"[{int(self.done/self.total_time*100): 3}%]" | |
def __str__(self): | |
mins = lambda t: t//60 | |
secs = lambda t: t%60 | |
duration = lambda t: f"{int(mins(t)):02}'{int(secs(t)):02}\"" | |
return f"{self.cycle_icon:<2} {self.cycle:>4} {duration(self.remaining) if self.remaining else 'done'}" | |
def tick(self): | |
self.done += 1 | |
print(f"\033[K{self}", end="\r") | |
self.filepath.write_text(str(self)) | |
@property | |
def cycle_icon(self): | |
''' return { | |
1: " ", | |
2: "¼", | |
3: "½", | |
4: "¾", | |
}.get(self.cycle_number, f"#{self.cycle_number}")''' | |
return f"{self.cycle_number}/{self.total_cycles}" | |
state = StateFile(Path("/home/ewen/.cache/pomodoro-state.txt")) | |
def countdown(time): # in seconds | |
state.total_time = time | |
while state.remaining: | |
state.tick() | |
sleep(1) | |
state.tick() | |
alert() | |
def alert(): | |
run("mpv /home/ewen/rocketbook/Argon.ogg --start=00:00:10", shell=True, capture_output=True) | |
def work(duration=25): | |
print(f"--- start {duration} mins work period ---") | |
state.cycle = "study" | |
countdown(duration * 60) | |
def pause(duration=5): | |
print(f"--- starting {duration} mins pause period ---") | |
state.cycle = "break" | |
countdown(duration * 60) | |
def cycle(work_duration=25, pause_duration=5): | |
state.cycle_number += 1 | |
work(work_duration) | |
pause(pause_duration) | |
def session(cycles: int = 4, work_for=25, pause_for=5, long_pause_for=20): | |
state.cycle_number = 0 | |
for i in range(cycles-1): | |
print(f"=== starting cycle #{i+1} ===") | |
cycle(work_for, pause_for) | |
print(f"=== starting last cycle! ===") | |
cycle(work_for, long_pause_for) | |
if __name__ == "__main__": | |
try: | |
opts = docopt(__doc__) | |
def opt(key, default=0): | |
return int(opts.get(key) or default) | |
if opt("--total-cycles"): | |
complete_sessions, remainder_cycles = divmod(opt("--total-cycles"), opt("--sessions-of")) | |
state.total_cycles = opt("--total-cycles") | |
for _ in range(complete_sessions): | |
session(cycles=opt("--sessions-of")) | |
session(cycles=remainder_cycles) | |
else: | |
state.total_cycles = opt('CYCLES', 4) | |
for i in range(opt('SESSIONS', 9999)): | |
print(f"~~~ Starting session #{i+1} ~~~") | |
session( | |
cycles=opt('CYCLES', 4), | |
work_for=opt('WORK', 25), | |
pause_for=opt('BREAK', 5), | |
long_pause_for=opt('PAUSE', 20), | |
) | |
except KeyboardInterrupt: | |
print() | |
print("bye") | |
state.filepath.unlink() | |
# TODO: use SIGUSR1 to toggle time remaining display |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment