timer-bot 1.7__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.7 → timer_bot-1.8}/CHANGELOG.rst +5 -0
- {timer-bot-1.7 → 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.7 → timer_bot-1.8}/src/timer_bot.py +148 -131
- {timer-bot-1.7 → timer_bot-1.8}/timer_bot.egg-info/SOURCES.txt +1 -2
- timer-bot-1.7/setup.cfg +0 -68
- timer-bot-1.7/setup.py +0 -4
- {timer-bot-1.7 → timer_bot-1.8}/LICENSE +0 -0
- {timer-bot-1.7 → timer_bot-1.8}/MANIFEST.in +0 -0
- {timer-bot-1.7 → timer_bot-1.8}/README.md +0 -0
- {timer-bot-1.7 → 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.11
|
|
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,19 +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:
|
|
197
223
|
logger.info("Failed to edit message: %s", e)
|
|
198
224
|
old_message = self.message
|
|
199
225
|
self.message = await self.channel.send(
|
|
200
226
|
embeds=embeds, components=components
|
|
201
227
|
)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
|
207
234
|
else:
|
|
208
235
|
self.message = await self.channel.send(embeds=embeds, components=components)
|
|
209
236
|
if self.thresholds and self.thresholds[-1] >= self.time_left >= 0:
|
|
@@ -236,29 +263,15 @@ class Timer:
|
|
|
236
263
|
return "time!"
|
|
237
264
|
|
|
238
265
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
"""Main message loop"""
|
|
242
|
-
if message.author.id == bot.me.id:
|
|
243
|
-
return
|
|
244
|
-
|
|
245
|
-
if message.content.lower().startswith("timer "):
|
|
246
|
-
await message.reply(
|
|
247
|
-
"This bot switched to slash commands. Use `/timer` instead."
|
|
248
|
-
)
|
|
249
|
-
|
|
266
|
+
TIMERS: dict[interactions.Snowflake : Timer] = {}
|
|
267
|
+
timer_base = interactions.SlashCommand(name="timer")
|
|
250
268
|
|
|
251
|
-
@bot.command(name="timer")
|
|
252
|
-
async def base_timer_command(ctx: interactions.CommandContext):
|
|
253
|
-
pass
|
|
254
269
|
|
|
255
|
-
|
|
256
|
-
def _get_prefix(ctx: interactions.CommandContext):
|
|
270
|
+
def _get_prefix(ctx: interactions.SlashContext):
|
|
257
271
|
"""Prefix used for log messages"""
|
|
258
272
|
if ctx.guild:
|
|
259
273
|
prefix = f"{ctx.guild.name}"
|
|
260
274
|
logger.debug("CTX: %s", ctx)
|
|
261
|
-
logger.debug("extras: %s", ctx._extras)
|
|
262
275
|
logger.debug("channel: %s", ctx.channel)
|
|
263
276
|
logger.debug("channel_id: %s", ctx.channel_id)
|
|
264
277
|
if ctx.channel:
|
|
@@ -268,36 +281,34 @@ def _get_prefix(ctx: interactions.CommandContext):
|
|
|
268
281
|
return prefix
|
|
269
282
|
|
|
270
283
|
|
|
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
|
-
|
|
296
|
-
),
|
|
297
|
-
],
|
|
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,
|
|
298
309
|
)
|
|
299
310
|
async def timer_start(
|
|
300
|
-
ctx: interactions.
|
|
311
|
+
ctx: interactions.SlashContext,
|
|
301
312
|
hours: int,
|
|
302
313
|
minutes: int = 0,
|
|
303
314
|
secured: bool = False,
|
|
@@ -306,9 +317,7 @@ async def timer_start(
|
|
|
306
317
|
# channel info will miss from threads and voice channels chats
|
|
307
318
|
# see https://github.com/interactions-py/library/issues/1041
|
|
308
319
|
if ctx.channel is interactions.MISSING:
|
|
309
|
-
ctx.channel =
|
|
310
|
-
_client=ctx.client, **(await ctx.client.get_channel(ctx.channel_id))
|
|
311
|
-
)
|
|
320
|
+
ctx.channel = await ctx.client.get_channel(ctx.channel_id)
|
|
312
321
|
prefix = _get_prefix(ctx)
|
|
313
322
|
# timer already running in channel
|
|
314
323
|
if ctx.channel_id in TIMERS:
|
|
@@ -329,7 +338,7 @@ async def timer_start(
|
|
|
329
338
|
logger.info(f"[{prefix}] Start timer: {hours}h {minutes}min")
|
|
330
339
|
try:
|
|
331
340
|
await timer.run()
|
|
332
|
-
except interactions.LibraryException:
|
|
341
|
+
except interactions.client.errors.LibraryException:
|
|
333
342
|
await ctx.edit(
|
|
334
343
|
"**Failed to start**\nTimer bot requires permission to send messages"
|
|
335
344
|
)
|
|
@@ -346,39 +355,37 @@ async def timer_start(
|
|
|
346
355
|
)
|
|
347
356
|
|
|
348
357
|
|
|
349
|
-
@
|
|
350
|
-
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):
|
|
351
360
|
"""Pause the timer"""
|
|
352
361
|
await _pause_timer(ctx)
|
|
353
362
|
|
|
354
363
|
|
|
355
|
-
@
|
|
356
|
-
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):
|
|
357
366
|
"""Resume the timer"""
|
|
358
367
|
await _resume_timer(ctx)
|
|
359
368
|
|
|
360
369
|
|
|
361
|
-
@
|
|
362
|
-
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):
|
|
363
372
|
"""Stop the timer"""
|
|
364
373
|
await _stop_timer(ctx)
|
|
365
374
|
|
|
366
375
|
|
|
367
|
-
@
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
options=[
|
|
371
|
-
interactions.Option(
|
|
372
|
-
name="minutes",
|
|
373
|
-
description="Number of minutes",
|
|
374
|
-
type=interactions.OptionType.INTEGER,
|
|
375
|
-
required=True,
|
|
376
|
-
min_value=1,
|
|
377
|
-
max_value=1440,
|
|
378
|
-
),
|
|
379
|
-
],
|
|
376
|
+
@timer_base.subcommand(
|
|
377
|
+
sub_cmd_name="add",
|
|
378
|
+
sub_cmd_description="Add time",
|
|
380
379
|
)
|
|
381
|
-
|
|
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):
|
|
382
389
|
"""Add time to the timer"""
|
|
383
390
|
timer = TIMERS.get(ctx.channel, None)
|
|
384
391
|
if not timer:
|
|
@@ -393,29 +400,25 @@ async def timer_add(ctx: interactions.CommandContext, minutes: int):
|
|
|
393
400
|
"This is a secured timer, only the owner can modify it.", ephemeral=True
|
|
394
401
|
)
|
|
395
402
|
return
|
|
396
|
-
|
|
397
|
-
timer.total_time += time
|
|
398
|
-
timer.time_left += time
|
|
403
|
+
timer.adjust_time(minutes * 60)
|
|
399
404
|
await timer.refresh(resume=False)
|
|
400
|
-
logger.info(f"[{prefix}] Added {
|
|
405
|
+
logger.info(f"[{prefix}] Added {minutes}min and refreshed")
|
|
401
406
|
await ctx.send(f"Time added ({minutes}min)")
|
|
402
407
|
|
|
403
408
|
|
|
404
|
-
@
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
),
|
|
416
|
-
],
|
|
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,
|
|
417
420
|
)
|
|
418
|
-
async def timer_sub(ctx: interactions.
|
|
421
|
+
async def timer_sub(ctx: interactions.SlashContext, minutes: int):
|
|
419
422
|
"""Substract time from the timer"""
|
|
420
423
|
timer = TIMERS.get(ctx.channel, None)
|
|
421
424
|
if not timer:
|
|
@@ -430,16 +433,16 @@ async def timer_sub(ctx: interactions.CommandContext, minutes: int):
|
|
|
430
433
|
"This is a secured timer, only the owner can modify it.", ephemeral=True
|
|
431
434
|
)
|
|
432
435
|
return
|
|
433
|
-
|
|
434
|
-
timer.total_time -= time
|
|
435
|
-
timer.time_left -= time
|
|
436
|
+
timer.adjust_time(-minutes * 60)
|
|
436
437
|
await timer.refresh(resume=False)
|
|
437
|
-
logger.info(f"[{prefix}] Substracted {
|
|
438
|
+
logger.info(f"[{prefix}] Substracted {minutes}min and refreshed")
|
|
438
439
|
await ctx.send(f"Time substracted ({minutes}min)")
|
|
439
440
|
|
|
440
441
|
|
|
441
|
-
@
|
|
442
|
-
|
|
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):
|
|
443
446
|
"""Discplay the timer anew"""
|
|
444
447
|
timer = TIMERS.get(ctx.channel, None)
|
|
445
448
|
if not timer:
|
|
@@ -458,41 +461,41 @@ button_pause = interactions.Button(
|
|
|
458
461
|
style=interactions.ButtonStyle.PRIMARY,
|
|
459
462
|
label="Pause",
|
|
460
463
|
custom_id="pause",
|
|
461
|
-
emoji=interactions.
|
|
464
|
+
emoji=interactions.PartialEmoji.from_str("⏱"),
|
|
462
465
|
)
|
|
463
466
|
|
|
464
467
|
button_resume = interactions.Button(
|
|
465
468
|
style=interactions.ButtonStyle.SUCCESS,
|
|
466
469
|
label="Resume",
|
|
467
470
|
custom_id="resume",
|
|
468
|
-
emoji=interactions.
|
|
471
|
+
emoji=interactions.PartialEmoji.from_str("▶️"),
|
|
469
472
|
)
|
|
470
473
|
|
|
471
474
|
button_stop = interactions.Button(
|
|
472
475
|
style=interactions.ButtonStyle.DANGER,
|
|
473
476
|
label="Stop",
|
|
474
477
|
custom_id="stop",
|
|
475
|
-
emoji=interactions.
|
|
478
|
+
emoji=interactions.PartialEmoji.from_str("🛑"),
|
|
476
479
|
)
|
|
477
480
|
|
|
478
481
|
|
|
479
|
-
@
|
|
482
|
+
@interactions.component_callback("pause")
|
|
480
483
|
async def button_pause_response(ctx: interactions.ComponentContext):
|
|
481
484
|
await _pause_timer(ctx)
|
|
482
485
|
|
|
483
486
|
|
|
484
|
-
@
|
|
487
|
+
@interactions.component_callback("resume")
|
|
485
488
|
async def button_resume_response(ctx: interactions.ComponentContext):
|
|
486
489
|
await _resume_timer(ctx)
|
|
487
490
|
|
|
488
491
|
|
|
489
|
-
@
|
|
492
|
+
@interactions.component_callback("stop")
|
|
490
493
|
async def button_stop_response(ctx: interactions.ComponentContext):
|
|
491
494
|
await _stop_timer(ctx)
|
|
492
495
|
|
|
493
496
|
|
|
494
497
|
async def _pause_timer(
|
|
495
|
-
ctx: Union[interactions.
|
|
498
|
+
ctx: Union[interactions.SlashContext, interactions.ComponentContext]
|
|
496
499
|
):
|
|
497
500
|
timer = TIMERS.get(ctx.channel, None)
|
|
498
501
|
if not timer:
|
|
@@ -519,7 +522,7 @@ async def _pause_timer(
|
|
|
519
522
|
|
|
520
523
|
|
|
521
524
|
async def _resume_timer(
|
|
522
|
-
ctx: Union[interactions.
|
|
525
|
+
ctx: Union[interactions.SlashContext, interactions.ComponentContext]
|
|
523
526
|
):
|
|
524
527
|
timer = TIMERS.get(ctx.channel, None)
|
|
525
528
|
if not timer:
|
|
@@ -540,7 +543,7 @@ async def _resume_timer(
|
|
|
540
543
|
|
|
541
544
|
|
|
542
545
|
async def _stop_timer(
|
|
543
|
-
ctx: Union[interactions.
|
|
546
|
+
ctx: Union[interactions.SlashContext, interactions.ComponentContext]
|
|
544
547
|
):
|
|
545
548
|
timer = TIMERS.get(ctx.channel, None)
|
|
546
549
|
if not timer:
|
|
@@ -558,6 +561,20 @@ async def _stop_timer(
|
|
|
558
561
|
await ctx.send("Timer stopped", ephemeral=True)
|
|
559
562
|
|
|
560
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
|
+
|
|
561
578
|
def main():
|
|
562
579
|
"""Entrypoint"""
|
|
563
580
|
logger.addHandler(logging.StreamHandler())
|
timer-bot-1.7/setup.cfg
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
[metadata]
|
|
2
|
-
name = timer-bot
|
|
3
|
-
version = 1.7
|
|
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.11
|
|
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<5
|
|
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.7/setup.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|