timer-bot 1.6__tar.gz → 1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {timer-bot-1.6 → timer_bot-1.8}/CHANGELOG.rst +11 -0
- {timer-bot-1.6 → timer_bot-1.8}/PKG-INFO +14 -16
- timer_bot-1.8/pyproject.toml +40 -0
- timer_bot-1.8/setup.cfg +4 -0
- {timer-bot-1.6 → timer_bot-1.8}/src/timer_bot.py +149 -130
- {timer-bot-1.6 → timer_bot-1.8}/timer_bot.egg-info/SOURCES.txt +1 -2
- timer-bot-1.6/setup.cfg +0 -68
- timer-bot-1.6/setup.py +0 -4
- {timer-bot-1.6 → timer_bot-1.8}/LICENSE +0 -0
- {timer-bot-1.6 → timer_bot-1.8}/MANIFEST.in +0 -0
- {timer-bot-1.6 → timer_bot-1.8}/README.md +0 -0
- {timer-bot-1.6 → timer_bot-1.8}/src/__init__.py +0 -0
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: timer-bot
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Classifier:
|
|
3
|
+
Version: 1.8
|
|
4
|
+
Summary: Discord Timer Bot
|
|
5
|
+
Author-email: Lionel Panhaleux <lionel.panhaleux+timer@gmail.com>
|
|
6
|
+
Project-URL: Repository, https://github.com/lionel-panhaleux/timer-bot
|
|
7
|
+
Keywords: Discord,timer
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
12
|
Classifier: Intended Audience :: Other Audience
|
|
12
13
|
Classifier: Natural Language :: English
|
|
13
14
|
Classifier: Operating System :: OS Independent
|
|
14
|
-
Classifier: Environment ::
|
|
15
|
-
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Topic :: Other/Nonlisted Topic
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Requires-Python: >=3.11
|
|
18
17
|
Description-Content-Type: text/markdown
|
|
19
18
|
License-File: LICENSE
|
|
20
|
-
Requires-Dist: discord-py-interactions
|
|
19
|
+
Requires-Dist: discord-py-interactions>5.13
|
|
20
|
+
Requires-Dist: uvloop>0.21
|
|
21
21
|
Provides-Extra: dev
|
|
22
22
|
Requires-Dist: black; extra == "dev"
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist: flake8; extra == "dev"
|
|
25
|
-
Requires-Dist: pytest; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff; extra == "dev"
|
|
26
24
|
Requires-Dist: zest.releaser[recommended]; extra == "dev"
|
|
27
25
|
|
|
28
26
|
# timer
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "timer-bot"
|
|
7
|
+
version = "1.8"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Lionel Panhaleux", email = "lionel.panhaleux+timer@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Discord Timer Bot"
|
|
12
|
+
keywords = ["Discord", "timer"]
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.11"
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Development Status :: 5 - Production/Stable",
|
|
20
|
+
"Intended Audience :: Other Audience",
|
|
21
|
+
"Natural Language :: English",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Environment :: Web Environment",
|
|
24
|
+
]
|
|
25
|
+
dependencies = ["discord-py-interactions>5.13", "uvloop>0.21"]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = ["black", "ruff", "zest.releaser[recommended]"]
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
timer-bot = "src.timer_bot:main"
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Repository = "https://github.com/lionel-panhaleux/timer-bot"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
include = ["src*"]
|
|
38
|
+
|
|
39
|
+
[tool.zest-releaser]
|
|
40
|
+
create-wheel = true
|
timer_bot-1.8/setup.cfg
ADDED
|
@@ -5,19 +5,35 @@ import os
|
|
|
5
5
|
|
|
6
6
|
import interactions
|
|
7
7
|
|
|
8
|
+
import interactions.api.events
|
|
9
|
+
import interactions.client.errors
|
|
10
|
+
|
|
8
11
|
|
|
9
12
|
logger = logging.getLogger()
|
|
10
13
|
bot = interactions.Client(
|
|
11
14
|
token=os.getenv("DISCORD_TOKEN") or "",
|
|
12
|
-
intents=interactions.Intents.
|
|
15
|
+
# intents=interactions.Intents.new(guild_messages=True),
|
|
16
|
+
delete_unused_application_cmds=True,
|
|
17
|
+
debug_scope=161406117686149120 if __debug__ else interactions.MISSING,
|
|
18
|
+
logging_level=logging.DEBUG if __debug__ else logging.INFO,
|
|
13
19
|
)
|
|
14
|
-
TIMERS = {}
|
|
15
20
|
|
|
16
21
|
|
|
17
|
-
@
|
|
22
|
+
@interactions.listen()
|
|
18
23
|
async def on_ready():
|
|
19
24
|
"""Login success"""
|
|
20
|
-
logger.info(f"Logged in as {bot.
|
|
25
|
+
logger.info(f"Logged in as {bot.user.username}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@interactions.listen()
|
|
29
|
+
async def on_startup():
|
|
30
|
+
"""Startup success"""
|
|
31
|
+
logger.info(f"Started")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@interactions.listen()
|
|
35
|
+
async def on_error(error: interactions.api.events.Error):
|
|
36
|
+
logger.error("API error: %s", error)
|
|
21
37
|
|
|
22
38
|
|
|
23
39
|
#: fixed list of times on which to send a notification
|
|
@@ -49,39 +65,47 @@ RUNNING_TIMER_HELP = (
|
|
|
49
65
|
class Timer:
|
|
50
66
|
"""Timer object: one per channel"""
|
|
51
67
|
|
|
52
|
-
def __init__(
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
channel: interactions.GuildChannel,
|
|
71
|
+
author: interactions.Member,
|
|
72
|
+
time: int,
|
|
73
|
+
secured: bool,
|
|
74
|
+
log_prefix: str = "",
|
|
75
|
+
):
|
|
53
76
|
self.channel = channel
|
|
54
77
|
self.author = author
|
|
55
78
|
self.secured = secured
|
|
56
|
-
self.start_time = 0
|
|
57
|
-
self.total_time =
|
|
58
|
-
self.time_left =
|
|
79
|
+
self.start_time: float = 0
|
|
80
|
+
self.total_time: int = 0
|
|
81
|
+
self.time_left: float = 0
|
|
59
82
|
self.log_prefix = log_prefix + "|internal"
|
|
60
|
-
self.thresholds = []
|
|
61
|
-
|
|
62
|
-
if time > limit:
|
|
63
|
-
self.thresholds.append(limit)
|
|
64
|
-
# add a threshold on every hour
|
|
65
|
-
for limit in range(1, time // 3600 + 1):
|
|
66
|
-
self.thresholds.append(limit * 3600)
|
|
83
|
+
self.thresholds: list[int] = []
|
|
84
|
+
self.adjust_time(time)
|
|
67
85
|
# internals
|
|
68
86
|
self.message: Optional[interactions.Message] = None
|
|
69
87
|
self.countdown_future = None # waiting for time to refresh
|
|
70
88
|
self.resume_future = None # waiting for resume
|
|
71
89
|
|
|
90
|
+
def adjust_time(self, time: int):
|
|
91
|
+
self.total_time += time
|
|
92
|
+
self.time_left += time
|
|
93
|
+
self.thresholds = [limit for limit in THRESHOLDS if self.time_left > limit]
|
|
94
|
+
# add a threshold on every hour
|
|
95
|
+
for limit in range(1, int(self.time_left // 3600) + 1):
|
|
96
|
+
self.thresholds.append(limit * 3600)
|
|
97
|
+
|
|
72
98
|
async def countdown(self):
|
|
73
99
|
"""Countdown: update embed, send notifications"""
|
|
74
100
|
while self.time_left > 0:
|
|
75
101
|
# update time_left
|
|
76
102
|
if not self.resume_future:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
self.total_time - max(0, bot._loop.time() - self.start_time),
|
|
80
|
-
)
|
|
103
|
+
time_spent = max(0, asyncio.get_event_loop().time() - self.start_time)
|
|
104
|
+
self.time_left = max(0, self.total_time - time_spent)
|
|
81
105
|
await self._send_or_update_message()
|
|
82
106
|
# update frequency depends on time left
|
|
83
107
|
if self.resume_future:
|
|
84
|
-
paused_time =
|
|
108
|
+
paused_time = asyncio.get_event_loop().time()
|
|
85
109
|
try:
|
|
86
110
|
logging.debug(f"[{self.log_prefix}] Wait for resume")
|
|
87
111
|
await self.resume_future
|
|
@@ -92,7 +116,7 @@ class Timer:
|
|
|
92
116
|
finally: # in any case resume.
|
|
93
117
|
logging.debug(f"[{self.log_prefix}] Timer resume")
|
|
94
118
|
self.resume_future = None
|
|
95
|
-
self.start_time +=
|
|
119
|
+
self.start_time += asyncio.get_event_loop().time() - paused_time
|
|
96
120
|
else:
|
|
97
121
|
if self.time_left < DISPLAY_SECONDS + 30:
|
|
98
122
|
# minimum because of Discord rate limitation
|
|
@@ -113,7 +137,7 @@ class Timer:
|
|
|
113
137
|
"""Run the timer, update the client.TIMERS map accordingly."""
|
|
114
138
|
logging.debug(f"[{self.log_prefix}] Run")
|
|
115
139
|
TIMERS[self.channel] = self
|
|
116
|
-
self.start_time =
|
|
140
|
+
self.start_time = asyncio.get_event_loop().time()
|
|
117
141
|
try:
|
|
118
142
|
await self.countdown()
|
|
119
143
|
except asyncio.CancelledError:
|
|
@@ -191,17 +215,22 @@ class Timer:
|
|
|
191
215
|
embeds = [interactions.Embed(title=title, description=description)]
|
|
192
216
|
if self.message:
|
|
193
217
|
try:
|
|
194
|
-
await self.message.edit(
|
|
218
|
+
self.message = await self.message.edit(
|
|
219
|
+
embeds=embeds, components=components
|
|
220
|
+
)
|
|
195
221
|
# messages older than 1h cannot be edited too much, at some point it fails
|
|
196
|
-
except interactions.LibraryException as e:
|
|
222
|
+
except interactions.errors.LibraryException as e:
|
|
223
|
+
logger.info("Failed to edit message: %s", e)
|
|
197
224
|
old_message = self.message
|
|
198
225
|
self.message = await self.channel.send(
|
|
199
226
|
embeds=embeds, components=components
|
|
200
227
|
)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
228
|
+
if old_message:
|
|
229
|
+
try:
|
|
230
|
+
await old_message.delete()
|
|
231
|
+
except interactions.errors.LibraryException as e:
|
|
232
|
+
logger.info("Failed to delete old message: %s", e)
|
|
233
|
+
pass
|
|
205
234
|
else:
|
|
206
235
|
self.message = await self.channel.send(embeds=embeds, components=components)
|
|
207
236
|
if self.thresholds and self.thresholds[-1] >= self.time_left >= 0:
|
|
@@ -234,29 +263,15 @@ class Timer:
|
|
|
234
263
|
return "time!"
|
|
235
264
|
|
|
236
265
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
"""Main message loop"""
|
|
240
|
-
if message.author.id == bot.me.id:
|
|
241
|
-
return
|
|
242
|
-
|
|
243
|
-
if message.content.lower().startswith("timer "):
|
|
244
|
-
await message.reply(
|
|
245
|
-
"This bot switched to slash commands. Use `/timer` instead."
|
|
246
|
-
)
|
|
247
|
-
|
|
266
|
+
TIMERS: dict[interactions.Snowflake : Timer] = {}
|
|
267
|
+
timer_base = interactions.SlashCommand(name="timer")
|
|
248
268
|
|
|
249
|
-
@bot.command(name="timer")
|
|
250
|
-
async def base_timer_command(ctx: interactions.CommandContext):
|
|
251
|
-
pass
|
|
252
269
|
|
|
253
|
-
|
|
254
|
-
def _get_prefix(ctx: interactions.CommandContext):
|
|
270
|
+
def _get_prefix(ctx: interactions.SlashContext):
|
|
255
271
|
"""Prefix used for log messages"""
|
|
256
272
|
if ctx.guild:
|
|
257
273
|
prefix = f"{ctx.guild.name}"
|
|
258
274
|
logger.debug("CTX: %s", ctx)
|
|
259
|
-
logger.debug("extras: %s", ctx._extras)
|
|
260
275
|
logger.debug("channel: %s", ctx.channel)
|
|
261
276
|
logger.debug("channel_id: %s", ctx.channel_id)
|
|
262
277
|
if ctx.channel:
|
|
@@ -266,36 +281,34 @@ def _get_prefix(ctx: interactions.CommandContext):
|
|
|
266
281
|
return prefix
|
|
267
282
|
|
|
268
283
|
|
|
269
|
-
@
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
),
|
|
295
|
-
],
|
|
284
|
+
@timer_base.subcommand(
|
|
285
|
+
sub_cmd_name="start",
|
|
286
|
+
sub_cmd_description="Start a timer",
|
|
287
|
+
)
|
|
288
|
+
@interactions.slash_option(
|
|
289
|
+
name="hours",
|
|
290
|
+
opt_type=interactions.OptionType.INTEGER,
|
|
291
|
+
description="Number of hours",
|
|
292
|
+
required=True,
|
|
293
|
+
min_value=0,
|
|
294
|
+
max_value=24,
|
|
295
|
+
)
|
|
296
|
+
@interactions.slash_option(
|
|
297
|
+
name="minutes",
|
|
298
|
+
opt_type=interactions.OptionType.INTEGER,
|
|
299
|
+
description="Number of minutes",
|
|
300
|
+
required=False,
|
|
301
|
+
min_value=0,
|
|
302
|
+
max_value=59,
|
|
303
|
+
)
|
|
304
|
+
@interactions.slash_option(
|
|
305
|
+
name="secured",
|
|
306
|
+
opt_type=interactions.OptionType.BOOLEAN,
|
|
307
|
+
description="Only the owner can modify a secure timer (default false)",
|
|
308
|
+
required=False,
|
|
296
309
|
)
|
|
297
310
|
async def timer_start(
|
|
298
|
-
ctx: interactions.
|
|
311
|
+
ctx: interactions.SlashContext,
|
|
299
312
|
hours: int,
|
|
300
313
|
minutes: int = 0,
|
|
301
314
|
secured: bool = False,
|
|
@@ -304,9 +317,7 @@ async def timer_start(
|
|
|
304
317
|
# channel info will miss from threads and voice channels chats
|
|
305
318
|
# see https://github.com/interactions-py/library/issues/1041
|
|
306
319
|
if ctx.channel is interactions.MISSING:
|
|
307
|
-
ctx.channel =
|
|
308
|
-
_client=ctx.client, **(await ctx.client.get_channel(ctx.channel_id))
|
|
309
|
-
)
|
|
320
|
+
ctx.channel = await ctx.client.get_channel(ctx.channel_id)
|
|
310
321
|
prefix = _get_prefix(ctx)
|
|
311
322
|
# timer already running in channel
|
|
312
323
|
if ctx.channel_id in TIMERS:
|
|
@@ -327,7 +338,7 @@ async def timer_start(
|
|
|
327
338
|
logger.info(f"[{prefix}] Start timer: {hours}h {minutes}min")
|
|
328
339
|
try:
|
|
329
340
|
await timer.run()
|
|
330
|
-
except interactions.LibraryException:
|
|
341
|
+
except interactions.client.errors.LibraryException:
|
|
331
342
|
await ctx.edit(
|
|
332
343
|
"**Failed to start**\nTimer bot requires permission to send messages"
|
|
333
344
|
)
|
|
@@ -344,39 +355,37 @@ async def timer_start(
|
|
|
344
355
|
)
|
|
345
356
|
|
|
346
357
|
|
|
347
|
-
@
|
|
348
|
-
async def timer_pause(ctx: interactions.
|
|
358
|
+
@timer_base.subcommand(sub_cmd_name="pause", sub_cmd_description="pause the timer")
|
|
359
|
+
async def timer_pause(ctx: interactions.SlashContext):
|
|
349
360
|
"""Pause the timer"""
|
|
350
361
|
await _pause_timer(ctx)
|
|
351
362
|
|
|
352
363
|
|
|
353
|
-
@
|
|
354
|
-
async def timer_resume(ctx: interactions.
|
|
364
|
+
@timer_base.subcommand(sub_cmd_name="resume", sub_cmd_description="resume the timer")
|
|
365
|
+
async def timer_resume(ctx: interactions.SlashContext):
|
|
355
366
|
"""Resume the timer"""
|
|
356
367
|
await _resume_timer(ctx)
|
|
357
368
|
|
|
358
369
|
|
|
359
|
-
@
|
|
360
|
-
async def timer_stop(ctx: interactions.
|
|
370
|
+
@timer_base.subcommand(sub_cmd_name="stop", sub_cmd_description="stop the timer")
|
|
371
|
+
async def timer_stop(ctx: interactions.SlashContext):
|
|
361
372
|
"""Stop the timer"""
|
|
362
373
|
await _stop_timer(ctx)
|
|
363
374
|
|
|
364
375
|
|
|
365
|
-
@
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
options=[
|
|
369
|
-
interactions.Option(
|
|
370
|
-
name="minutes",
|
|
371
|
-
description="Number of minutes",
|
|
372
|
-
type=interactions.OptionType.INTEGER,
|
|
373
|
-
required=True,
|
|
374
|
-
min_value=1,
|
|
375
|
-
max_value=1440,
|
|
376
|
-
),
|
|
377
|
-
],
|
|
376
|
+
@timer_base.subcommand(
|
|
377
|
+
sub_cmd_name="add",
|
|
378
|
+
sub_cmd_description="Add time",
|
|
378
379
|
)
|
|
379
|
-
|
|
380
|
+
@interactions.slash_option(
|
|
381
|
+
name="minutes",
|
|
382
|
+
opt_type=interactions.OptionType.INTEGER,
|
|
383
|
+
description="Number of minutes",
|
|
384
|
+
required=True,
|
|
385
|
+
min_value=1,
|
|
386
|
+
max_value=1440,
|
|
387
|
+
)
|
|
388
|
+
async def timer_add(ctx: interactions.SlashContext, minutes: int):
|
|
380
389
|
"""Add time to the timer"""
|
|
381
390
|
timer = TIMERS.get(ctx.channel, None)
|
|
382
391
|
if not timer:
|
|
@@ -391,29 +400,25 @@ async def timer_add(ctx: interactions.CommandContext, minutes: int):
|
|
|
391
400
|
"This is a secured timer, only the owner can modify it.", ephemeral=True
|
|
392
401
|
)
|
|
393
402
|
return
|
|
394
|
-
|
|
395
|
-
timer.total_time += time
|
|
396
|
-
timer.time_left += time
|
|
403
|
+
timer.adjust_time(minutes * 60)
|
|
397
404
|
await timer.refresh(resume=False)
|
|
398
|
-
logger.info(f"[{prefix}] Added {
|
|
405
|
+
logger.info(f"[{prefix}] Added {minutes}min and refreshed")
|
|
399
406
|
await ctx.send(f"Time added ({minutes}min)")
|
|
400
407
|
|
|
401
408
|
|
|
402
|
-
@
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
),
|
|
414
|
-
],
|
|
409
|
+
@timer_base.subcommand(
|
|
410
|
+
sub_cmd_name="sub",
|
|
411
|
+
sub_cmd_description="Substract time",
|
|
412
|
+
)
|
|
413
|
+
@interactions.slash_option(
|
|
414
|
+
name="minutes",
|
|
415
|
+
opt_type=interactions.OptionType.INTEGER,
|
|
416
|
+
description="Number of minutes",
|
|
417
|
+
required=True,
|
|
418
|
+
min_value=1,
|
|
419
|
+
max_value=1440,
|
|
415
420
|
)
|
|
416
|
-
async def timer_sub(ctx: interactions.
|
|
421
|
+
async def timer_sub(ctx: interactions.SlashContext, minutes: int):
|
|
417
422
|
"""Substract time from the timer"""
|
|
418
423
|
timer = TIMERS.get(ctx.channel, None)
|
|
419
424
|
if not timer:
|
|
@@ -428,16 +433,16 @@ async def timer_sub(ctx: interactions.CommandContext, minutes: int):
|
|
|
428
433
|
"This is a secured timer, only the owner can modify it.", ephemeral=True
|
|
429
434
|
)
|
|
430
435
|
return
|
|
431
|
-
|
|
432
|
-
timer.total_time -= time
|
|
433
|
-
timer.time_left -= time
|
|
436
|
+
timer.adjust_time(-minutes * 60)
|
|
434
437
|
await timer.refresh(resume=False)
|
|
435
|
-
logger.info(f"[{prefix}] Substracted {
|
|
438
|
+
logger.info(f"[{prefix}] Substracted {minutes}min and refreshed")
|
|
436
439
|
await ctx.send(f"Time substracted ({minutes}min)")
|
|
437
440
|
|
|
438
441
|
|
|
439
|
-
@
|
|
440
|
-
|
|
442
|
+
@timer_base.subcommand(
|
|
443
|
+
sub_cmd_name="display", sub_cmd_description="Display the timer anew"
|
|
444
|
+
)
|
|
445
|
+
async def timer_display(ctx: interactions.SlashContext):
|
|
441
446
|
"""Discplay the timer anew"""
|
|
442
447
|
timer = TIMERS.get(ctx.channel, None)
|
|
443
448
|
if not timer:
|
|
@@ -456,41 +461,41 @@ button_pause = interactions.Button(
|
|
|
456
461
|
style=interactions.ButtonStyle.PRIMARY,
|
|
457
462
|
label="Pause",
|
|
458
463
|
custom_id="pause",
|
|
459
|
-
emoji=interactions.
|
|
464
|
+
emoji=interactions.PartialEmoji.from_str("⏱"),
|
|
460
465
|
)
|
|
461
466
|
|
|
462
467
|
button_resume = interactions.Button(
|
|
463
468
|
style=interactions.ButtonStyle.SUCCESS,
|
|
464
469
|
label="Resume",
|
|
465
470
|
custom_id="resume",
|
|
466
|
-
emoji=interactions.
|
|
471
|
+
emoji=interactions.PartialEmoji.from_str("▶️"),
|
|
467
472
|
)
|
|
468
473
|
|
|
469
474
|
button_stop = interactions.Button(
|
|
470
475
|
style=interactions.ButtonStyle.DANGER,
|
|
471
476
|
label="Stop",
|
|
472
477
|
custom_id="stop",
|
|
473
|
-
emoji=interactions.
|
|
478
|
+
emoji=interactions.PartialEmoji.from_str("🛑"),
|
|
474
479
|
)
|
|
475
480
|
|
|
476
481
|
|
|
477
|
-
@
|
|
482
|
+
@interactions.component_callback("pause")
|
|
478
483
|
async def button_pause_response(ctx: interactions.ComponentContext):
|
|
479
484
|
await _pause_timer(ctx)
|
|
480
485
|
|
|
481
486
|
|
|
482
|
-
@
|
|
487
|
+
@interactions.component_callback("resume")
|
|
483
488
|
async def button_resume_response(ctx: interactions.ComponentContext):
|
|
484
489
|
await _resume_timer(ctx)
|
|
485
490
|
|
|
486
491
|
|
|
487
|
-
@
|
|
492
|
+
@interactions.component_callback("stop")
|
|
488
493
|
async def button_stop_response(ctx: interactions.ComponentContext):
|
|
489
494
|
await _stop_timer(ctx)
|
|
490
495
|
|
|
491
496
|
|
|
492
497
|
async def _pause_timer(
|
|
493
|
-
ctx: Union[interactions.
|
|
498
|
+
ctx: Union[interactions.SlashContext, interactions.ComponentContext]
|
|
494
499
|
):
|
|
495
500
|
timer = TIMERS.get(ctx.channel, None)
|
|
496
501
|
if not timer:
|
|
@@ -517,7 +522,7 @@ async def _pause_timer(
|
|
|
517
522
|
|
|
518
523
|
|
|
519
524
|
async def _resume_timer(
|
|
520
|
-
ctx: Union[interactions.
|
|
525
|
+
ctx: Union[interactions.SlashContext, interactions.ComponentContext]
|
|
521
526
|
):
|
|
522
527
|
timer = TIMERS.get(ctx.channel, None)
|
|
523
528
|
if not timer:
|
|
@@ -538,7 +543,7 @@ async def _resume_timer(
|
|
|
538
543
|
|
|
539
544
|
|
|
540
545
|
async def _stop_timer(
|
|
541
|
-
ctx: Union[interactions.
|
|
546
|
+
ctx: Union[interactions.SlashContext, interactions.ComponentContext]
|
|
542
547
|
):
|
|
543
548
|
timer = TIMERS.get(ctx.channel, None)
|
|
544
549
|
if not timer:
|
|
@@ -556,6 +561,20 @@ async def _stop_timer(
|
|
|
556
561
|
await ctx.send("Timer stopped", ephemeral=True)
|
|
557
562
|
|
|
558
563
|
|
|
564
|
+
bot.add_listener(on_ready)
|
|
565
|
+
bot.add_listener(on_startup)
|
|
566
|
+
bot.add_command(timer_start)
|
|
567
|
+
bot.add_command(timer_stop)
|
|
568
|
+
bot.add_command(timer_pause)
|
|
569
|
+
bot.add_command(timer_resume)
|
|
570
|
+
bot.add_command(timer_display)
|
|
571
|
+
bot.add_command(timer_add)
|
|
572
|
+
bot.add_command(timer_sub)
|
|
573
|
+
bot.add_component_callback(button_pause_response)
|
|
574
|
+
bot.add_component_callback(button_resume_response)
|
|
575
|
+
bot.add_component_callback(button_stop_response)
|
|
576
|
+
|
|
577
|
+
|
|
559
578
|
def main():
|
|
560
579
|
"""Entrypoint"""
|
|
561
580
|
logger.addHandler(logging.StreamHandler())
|
timer-bot-1.6/setup.cfg
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
[metadata]
|
|
2
|
-
name = timer-bot
|
|
3
|
-
version = 1.6
|
|
4
|
-
author = lionelpx
|
|
5
|
-
author_email = lionel.panhaleux@gmail.com
|
|
6
|
-
url = http://github.com/lionel-panhaleux/timer-bot
|
|
7
|
-
description = "Discord Timer Bot",
|
|
8
|
-
long_description = file: README.md
|
|
9
|
-
long_description_content_type = text/markdown
|
|
10
|
-
license = "MIT"
|
|
11
|
-
keywords = discord game timer
|
|
12
|
-
classifiers =
|
|
13
|
-
Development Status :: 4 - Beta
|
|
14
|
-
Intended Audience :: Other Audience
|
|
15
|
-
Natural Language :: English
|
|
16
|
-
Operating System :: OS Independent
|
|
17
|
-
Environment :: Console
|
|
18
|
-
Programming Language :: Python :: 3
|
|
19
|
-
Programming Language :: Python :: 3.8
|
|
20
|
-
Topic :: Other/Nonlisted Topic
|
|
21
|
-
|
|
22
|
-
[options]
|
|
23
|
-
zip_safe = True
|
|
24
|
-
include_package_data = True
|
|
25
|
-
packages = find:
|
|
26
|
-
setup_requires =
|
|
27
|
-
setuptools
|
|
28
|
-
install_requires =
|
|
29
|
-
discord-py-interactions>=4.4.1
|
|
30
|
-
|
|
31
|
-
[options.entry_points]
|
|
32
|
-
console_scripts =
|
|
33
|
-
timer-bot = src.timer_bot:main
|
|
34
|
-
|
|
35
|
-
[options.extras_require]
|
|
36
|
-
dev =
|
|
37
|
-
black
|
|
38
|
-
doc8
|
|
39
|
-
flake8
|
|
40
|
-
pytest
|
|
41
|
-
zest.releaser[recommended]
|
|
42
|
-
|
|
43
|
-
[options.packages.find]
|
|
44
|
-
exclude =
|
|
45
|
-
tests
|
|
46
|
-
|
|
47
|
-
[flake8]
|
|
48
|
-
max-line-length = 88
|
|
49
|
-
exclude = build, dist
|
|
50
|
-
ignore = E203, W503
|
|
51
|
-
|
|
52
|
-
[bdist_wheel]
|
|
53
|
-
python-tag = py3
|
|
54
|
-
|
|
55
|
-
[distutils]
|
|
56
|
-
index-servers = pypi
|
|
57
|
-
|
|
58
|
-
[tool:pytest]
|
|
59
|
-
filterwarnings =
|
|
60
|
-
ignore:.*format string will parse more strictly.*:DeprecationWarning
|
|
61
|
-
|
|
62
|
-
[zest.releaser]
|
|
63
|
-
create-wheel = yes
|
|
64
|
-
|
|
65
|
-
[egg_info]
|
|
66
|
-
tag_build =
|
|
67
|
-
tag_date = 0
|
|
68
|
-
|
timer-bot-1.6/setup.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|