-
Notifications
You must be signed in to change notification settings - Fork 2
/
countdown
executable file
·157 lines (124 loc) · 4.23 KB
/
countdown
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env python3
import argparse
import re
import subprocess
import sys
from datetime import datetime, time, timedelta
from time import sleep
def seconds_until(time_str):
"""
Calculates the number of seconds remaining until the time specified by the
given string is reached.
Args:
time_str: string representing the target time.
Returns:
The calculated number of seconds, or -1 in case of error.
"""
try:
target_time = time(*(map(int, time_str.split(':'))))
except ValueError:
return -1
target_datetime = datetime.combine(datetime.today(), target_time)
seconds_delta = int((target_datetime - datetime.now()).total_seconds())
if seconds_delta < 0:
# We're already past the target time today, so we'll countdown until
# the given time the next day
seconds_delta = 86400 + seconds_delta
return seconds_delta
def seconds_in(time_str):
"""
Calculates the number of seconds corresponding to the time duration
specified by the given string.
Args:
time_str: string representing the time duration.
Returns:
The calculated number of seconds, or -1 in case of error.
"""
regex = re.compile(
r'((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?$')
time_parts = regex.match(time_str)
if not time_parts:
return -1
time_parts = time_parts.groupdict()
# If time_str was initially `2h3m50s`, then time_parts will now be
# `{'hours': '2', 'seconds': '50', 'minutes': '3'}`
time_params = {}
for (name, param) in time_parts.items():
if param:
time_params[name] = int(param)
seconds = int(timedelta(**time_params).total_seconds())
# An erroneous input results in seconds being zero here. This should
# probably be caught earlier (i.e. when parsing the regular expression
# itself). Doing so will also allow us to remove the `if time_str == '0s'`
# check at the beginning of the function.
if seconds == 0:
return -1
return seconds
def calculate_seconds(time_str):
"""
Calculates the number of seconds corresponding to the given string. The
given string can either be a target time (e.g. 20:30) or a string
representing a time duration (e.g. 2h45m).
Args:
time_str: string representing the time or time duration.
Returns:
The calculated number of seconds.
"""
# Plain integers are assumed to be seconds
try:
seconds = int(time_str)
return seconds
except ValueError:
pass
if time_str == '0s':
return 0
if ':' in time_str:
return seconds_until(time_str)
else:
return seconds_in(time_str)
# Set up command line arguments
parser = argparse.ArgumentParser(
usage='%(prog)s [ARGUMENTS]',
description='Start a countdown for the given time duration'
)
parser.add_argument(
'time',
help='time until or time-duration for which the countdown should run'
)
parser.add_argument(
'message',
nargs='?',
default='Countdown complete!',
help='message to be displayed when the countdown completes'
)
args = parser.parse_args()
seconds = calculate_seconds(args.time)
if seconds > 0:
finishing_time = (datetime.now()
+ timedelta(seconds=seconds)).strftime('%Y-%m-%d %H:%M:%S')
print("Counting down {} seconds until {}".format(seconds, finishing_time))
elif seconds < 0:
print("Unable to parse time duration '{}'".format(args.time))
sys.exit(1)
while 1:
try:
while seconds > 0:
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
sys.stdout.write("%02d:%02d:%02d" % (h, m, s))
sys.stdout.flush()
sleep(1.0)
sys.stdout.write("\r\033[K")
seconds -= 1
print("Countdown complete!")
ret = subprocess.call(['xmessage', '-buttons', 'Okay:0,Snooze 10 minutes:1', args.message])
if ret == 0:
break
print("Snoozing for 10 minutes...")
seconds = 600
except KeyboardInterrupt:
sys.stdout.write("\r\033[K")
sys.stdout.write("%02d:%02d:%02d" % (h, m, s))
sys.stdout.flush()
print("\nCountdown stopped manually")
break