История изменений
Исправление neumond, (текущая версия) :
Я себе похожее наговнякал, запускаю примерно так:
timer 5m ; alarm blabla
alarm тоже скрипт, там notify-send и mpv звук звонка. По сути красивый sleep, показывающий сколько там осталось.
import argparse
import re
import sys
from time import monotonic_ns, sleep
T_RE = re.compile(r'^(\d+)([wdhms])')
KMAP = {
'w': 604800,
'd': 86400,
'h': 3600,
'm': 60,
's': 1,
}
def create_parser():
p = argparse.ArgumentParser()
p.add_argument('timespec', nargs='+', help=(
'Example: 1d 5h 45m; '
's: seconds; '
'm: minutes; '
'h: hours; '
'd: days; '
'w: weeks'
))
return p
def error(msg, exitcode=1):
print(msg, file=sys.stderr)
exit(exitcode)
def parse_timespec(tsp):
seconds = 0
for part in tsp:
part = part.lower().strip()
while part:
if (m := T_RE.match(part)) is None:
error(f'Unrecognized part: {part}')
n, unit = m.group(1), m.group(2)
seconds += int(n) * KMAP[unit]
part = part[m.end():].lstrip()
return seconds
def _mod(ts, d):
return ts % d, ts // d
def time_string(t, total):
percent = 1000 - t * 1000 // total
percent = f'{percent // 10:>02}.{percent % 10:>01}%'
s, t = _mod(t, 60)
m, t = _mod(t, 60)
h, d = _mod(t, 24)
r = ''
if d == 1:
r = '1 day '
elif d > 1:
r = f'{d} days '
return r + f'{h:>02}:{m:>02}:{s:>02} {percent} '
def print_same_line(text):
print('\x1B[2K\x0D' + text, end='')
def main(args):
seconds = parse_timespec(args.timespec)
try:
until = monotonic_ns() + seconds * 1_000_000_000
while (t := monotonic_ns()) <= until:
print_same_line(time_string(
(until - t) // 1_000_000_000,
seconds))
sleep(1)
print_same_line('Timer went off')
print()
except KeyboardInterrupt:
print_same_line('')
error('Timer has been cancelled')
if __name__ == '__main__':
main(create_parser().parse_args())
Исходная версия neumond, :
Я себе похожее наговнякал, запускаю примерно так:
timer 5m ; alarm blabla
alarm тоже скрипт, там notify-send и mpv звук звонка. По сути красивый sleep, показывающий сколько там осталось.
import argparse
import re
import sys
from time import monotonic_ns, sleep
T_RE = re.compile(r'^(\d+)([wdhms])')
KMAP = {
'w': 604800,
'd': 86400,
'h': 3600,
'm': 60,
's': 1,
}
def non_empty_str(v):
if not v.strip():
raise ValueError
return v
def create_parser():
p = argparse.ArgumentParser()
p.add_argument('timespec', nargs='+', help=(
'Example: 1d 5h 45m; '
's: seconds; '
'm: minutes; '
'h: hours; '
'd: days; '
'w: weeks'
))
return p
def error(msg, exitcode=1):
print(msg, file=sys.stderr)
exit(exitcode)
def parse_timespec(tsp):
seconds = 0
for part in tsp:
part = part.lower().strip()
while part:
if (m := T_RE.match(part)) is None:
error(f'Unrecognized part: {part}')
n, unit = m.group(1), m.group(2)
seconds += int(n) * KMAP[unit]
part = part[m.end():].lstrip()
return seconds
def _mod(ts, d):
return ts % d, ts // d
def time_string(t, total):
percent = 1000 - t * 1000 // total
percent = f'{percent // 10:>02}.{percent % 10:>01}%'
s, t = _mod(t, 60)
m, t = _mod(t, 60)
h, d = _mod(t, 24)
r = ''
if d == 1:
r = '1 day '
elif d > 1:
r = f'{d} days '
return r + f'{h:>02}:{m:>02}:{s:>02} {percent} '
def print_same_line(text):
print('\x1B[2K\x0D' + text, end='')
def main(args):
seconds = parse_timespec(args.timespec)
try:
until = monotonic_ns() + seconds * 1_000_000_000
while (t := monotonic_ns()) <= until:
print_same_line(time_string(
(until - t) // 1_000_000_000,
seconds))
sleep(1)
print_same_line('Timer went off')
print()
except KeyboardInterrupt:
print_same_line('')
error('Timer has been cancelled')
if __name__ == '__main__':
main(create_parser().parse_args())