dshellInterpreter 0.2.8.2__py3-none-any.whl → 0.2.9.1__py3-none-any.whl

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.

Potentially problematic release.


This version of dshellInterpreter might be problematic. Click here for more details.

@@ -2,18 +2,151 @@ from asyncio import sleep
2
2
  from re import search
3
3
  from typing import Union
4
4
 
5
- from discord import MISSING, PermissionOverwrite, Member, Role, Message
5
+ from discord import MISSING, PermissionOverwrite, Member, Role, Message, Thread
6
6
  from discord.utils import _MissingSentinel
7
+ from discord import NotFound
7
8
 
8
9
  __all__ = [
10
+ 'dshell_get_channel',
11
+ 'dshell_get_channels',
12
+ 'dshell_get_thread',
13
+ 'dshell_get_channels_in_category',
9
14
  'dshell_create_text_channel',
15
+ 'dshell_create_thread_message',
10
16
  'dshell_delete_channel',
11
17
  'dshell_delete_channels',
18
+ 'dshell_delete_thread',
12
19
  'dshell_create_voice_channel',
13
20
  'dshell_edit_text_channel',
14
- 'dshell_edit_voice_channel'
21
+ 'dshell_edit_voice_channel',
22
+ 'dshell_edit_thread'
15
23
  ]
16
24
 
25
+ async def utils_get_message(ctx: Message, message: Union[int, str]) -> Message:
26
+ """
27
+ Returns the message object of the specified message ID or link.
28
+ Message is only available in the same server as the command and in the same channel.
29
+ If the message is a link, it must be in the format: https://discord.com/channels/{guild_id}/{channel_id}/{message_id}
30
+ """
31
+
32
+ if isinstance(message, int):
33
+ return await ctx.channel.fetch_message(message)
34
+
35
+ elif isinstance(message, str):
36
+ match = search(r'https://discord\.com/channels/(\d+)/(\d+)/(\d+)', message)
37
+ if not match:
38
+ raise Exception("Invalid message link format. Use a valid Discord message link.")
39
+ guild_id = int(match.group(1))
40
+ channel_id = int(match.group(2))
41
+ message_id = int(match.group(3))
42
+
43
+ if guild_id != ctx.guild.id:
44
+ raise Exception("The message must be from the same server as the command !")
45
+
46
+ return await ctx.guild.get_channel(channel_id).fetch_message(message_id)
47
+
48
+ raise Exception(f"Message must be an integer or a string, not {type(message)} !")
49
+
50
+ async def utils_get_thread(ctx: Message, thread: Union[int, str]) -> Thread:
51
+ """
52
+ Returns the thread object of the specified thread ID or link.
53
+ Thread is only available in the same server as the command and in the same channel.
54
+ If the thread is a link, it must be in the format: https://discord.com/channels/{guild_id}/{channel_id}/{message_id}
55
+ """
56
+
57
+ if isinstance(thread, int):
58
+ return ctx.channel.get_thread(thread)
59
+
60
+ elif isinstance(thread, str):
61
+ match = search(r'https://discord\.com/channels/(\d+)/(\d+)(/\d+)?', thread)
62
+ if not match:
63
+ raise Exception("Invalid thread link format. Use a valid Discord thread link.")
64
+ guild_id = int(match.group(1))
65
+ message_id = int(match.group(2))
66
+ channel_id = ctx.channel.id if len(match.groups()) == 3 else ctx.channel.id
67
+
68
+ if guild_id != ctx.guild.id:
69
+ raise Exception("The thread must be from the same server as the command !")
70
+
71
+ try:
72
+ c = await ctx.guild.get_channel(channel_id).fetch_message(message_id)
73
+ return c.thread
74
+ except NotFound:
75
+ raise Exception(f"Thread with ID {message_id} not found in channel {channel_id} !")
76
+
77
+ raise Exception(f"Thread must be an integer or a string, not {type(thread)} !")
78
+
79
+
80
+ async def dshell_get_channel(ctx: Message, name):
81
+ """
82
+ Returns the channel object of the channel where the command was executed or the specified channel.
83
+ """
84
+
85
+ if isinstance(name, str):
86
+ return next((c.id for c in ctx.channel.guild.channels if c.name == name), None)
87
+
88
+ raise Exception(f"Channel must be an integer or a string, not {type(name)} !")
89
+
90
+
91
+ async def dshell_get_channels(ctx: Message, name=None, regex=None):
92
+ """
93
+ Returns a list of channels with the same name and/or matching the same regex.
94
+ If neither is set, it will return all channels in the server.
95
+ """
96
+ if name is not None and not isinstance(name, str):
97
+ raise Exception(f"Name must be a string, not {type(name)} !")
98
+
99
+ if regex is not None and not isinstance(regex, str):
100
+ raise Exception(f"Regex must be a string, not {type(regex)} !")
101
+
102
+ from .._DshellParser.ast_nodes import ListNode
103
+ channels = ListNode([])
104
+
105
+ for channel in ctx.channel.guild.channels:
106
+ if name is not None and channel.name == str(name):
107
+ channels.add(channel.id)
108
+
109
+ elif regex is not None and search(regex, channel.name):
110
+ channels.add(channel.id)
111
+
112
+ return channels
113
+
114
+ async def dshell_get_channels_in_category(ctx: Message, category=None, name=None, regex=None):
115
+ """
116
+ Returns a list of channels in a specific category with the same name and/or matching the same regex.
117
+ If neither is set, it will return all channels in the specified category.
118
+ """
119
+
120
+ if category is None and ctx.channel.category is not None:
121
+ category = ctx.channel.category.id
122
+
123
+ if category is None:
124
+ raise Exception("Category must be specified !")
125
+
126
+ if not isinstance(category, int):
127
+ raise Exception(f"Category must be an integer, not {type(category)} !")
128
+
129
+ if name is not None and not isinstance(name, str):
130
+ raise Exception(f"Name must be a string, not {type(name)} !")
131
+
132
+ if regex is not None and not isinstance(regex, str):
133
+ raise Exception(f"Regex must be a string, not {type(regex)} !")
134
+
135
+ from .._DshellParser.ast_nodes import ListNode
136
+ channels = ListNode([])
137
+
138
+ category_channel = ctx.channel.guild.get_channel(category)
139
+ if category_channel is None or not hasattr(category_channel, 'channels'):
140
+ raise Exception(f"Category {category} not found or does not contain channels !")
141
+
142
+ for channel in category_channel.channels:
143
+ if name is not None and channel.name == str(name):
144
+ channels.add(channel.id)
145
+
146
+ elif regex is not None and search(regex, channel.name):
147
+ channels.add(channel.id)
148
+
149
+ return channels
17
150
 
18
151
  async def dshell_create_text_channel(ctx: Message,
19
152
  name,
@@ -191,3 +324,119 @@ async def dshell_edit_voice_channel(ctx: Message,
191
324
  reason=reason)
192
325
 
193
326
  return channel_to_edit.id
327
+
328
+
329
+ async def dshell_create_thread_message(ctx: Message,
330
+ name,
331
+ message: Union[int, str] = None,
332
+ archive=MISSING,
333
+ slowmode=MISSING):
334
+ """
335
+ Creates a thread from a message.
336
+ """
337
+
338
+ if message is None:
339
+ message = ctx.id
340
+
341
+ message = await utils_get_message(ctx, message)
342
+
343
+
344
+ if not isinstance(name, str):
345
+ raise Exception(f"Name must be a string, not {type(name)} !")
346
+
347
+ if not isinstance(archive, _MissingSentinel) and not isinstance(archive, int):
348
+ raise Exception(f"Auto archive duration must be an integer, not {type(archive)} !")
349
+
350
+ if not isinstance(archive, _MissingSentinel) and archive not in (60, 1440, 4320, 10080):
351
+ raise Exception("Auto archive duration must be one of the following values: 60, 1440, 4320, 10080 !")
352
+
353
+ if not isinstance(slowmode, _MissingSentinel) and not isinstance(slowmode, int):
354
+ raise Exception(f"Slowmode delay must be an integer, not {type(slowmode)} !")
355
+
356
+ if not isinstance(slowmode, _MissingSentinel) and slowmode < 0:
357
+ raise Exception("Slowmode delay must be a positive integer !")
358
+
359
+ thread = await message.create_thread(name=name,
360
+ auto_archive_duration=archive,
361
+ slowmode_delay=slowmode)
362
+
363
+ return thread.id
364
+
365
+ async def dshell_edit_thread(ctx: Message,
366
+ thread: Union[int, str] = None,
367
+ name=None,
368
+ archive=MISSING,
369
+ slowmode=MISSING,
370
+ reason=None):
371
+ """ Edits a thread.
372
+ """
373
+ if thread is None:
374
+ thread = ctx.thread
375
+
376
+ if thread is None:
377
+ raise Exception("Thread must be specified !")
378
+
379
+ thread = await utils_get_thread(ctx, thread)
380
+
381
+ if not isinstance(name, _MissingSentinel) and not isinstance(name, str):
382
+ raise Exception(f"Name must be a string, not {type(name)} !")
383
+
384
+ if not isinstance(archive, _MissingSentinel) and not isinstance(archive, int):
385
+ raise Exception(f"Auto archive duration must be an integer, not {type(archive)} !")
386
+
387
+ if not isinstance(archive, _MissingSentinel) and archive not in (60, 1440, 4320, 10080):
388
+ raise Exception("Auto archive duration must be one of the following values: 60, 1440, 4320, 10080 !")
389
+
390
+ if not isinstance(slowmode, _MissingSentinel) and not isinstance(slowmode, int):
391
+ raise Exception(f"Slowmode delay must be an integer, not {type(slowmode)} !")
392
+
393
+ if not isinstance(slowmode, _MissingSentinel) and slowmode < 0:
394
+ raise Exception("Slowmode delay must be a positive integer !")
395
+
396
+ await thread.edit(name=name if name is not None else thread.name,
397
+ auto_archive_duration=archive if archive is not MISSING else thread.auto_archive_duration,
398
+ slowmode_delay=slowmode if slowmode is not MISSING else thread.slowmode_delay,
399
+ reason=reason)
400
+
401
+
402
+ async def dshell_get_thread(ctx: Message, message: Union[int, str] = None):
403
+ """
404
+ Returns the thread object of the specified thread ID.
405
+ """
406
+
407
+ if message is None:
408
+ message = ctx.id
409
+
410
+ message = await utils_get_message(ctx, message)
411
+
412
+ if not hasattr(message, 'thread'):
413
+ return None
414
+
415
+ thread = message.thread
416
+
417
+ if thread is None:
418
+ return None
419
+
420
+ return thread.id
421
+
422
+
423
+ async def dshell_delete_thread(ctx: Message, thread: Union[int, str] = None, reason=None):
424
+ """
425
+ Deletes a thread.
426
+ """
427
+
428
+ if thread is None:
429
+ thread = ctx.id
430
+
431
+ thread = await utils_get_message(ctx, thread)
432
+
433
+ if not hasattr(thread, 'thread'):
434
+ raise Exception("The specified message does not have a thread !")
435
+
436
+ if thread.thread is None:
437
+ raise Exception("The specified message does not have a thread !")
438
+
439
+ await thread.thread.delete(reason=reason)
440
+
441
+ return thread.thread.id
442
+
@@ -1,8 +1,9 @@
1
1
  from datetime import timedelta, datetime, UTC
2
2
 
3
- from discord import MISSING, Message, Member, Permissions, Role
3
+ from discord import MISSING, Message, Member, Permissions, Role, Embed
4
4
 
5
5
  __all__ = [
6
+ "dshell_send_private_message",
6
7
  "dshell_ban_member",
7
8
  "dshell_unban_member",
8
9
  "dshell_kick_member",
@@ -16,6 +17,35 @@ __all__ = [
16
17
  "dshell_remove_member_roles"
17
18
  ]
18
19
 
20
+ async def dshell_send_private_message(ctx: Message, member: int = None, message: str = None, delete: int = None, embeds = None, ):
21
+ """
22
+ Sends a private message to a member.
23
+ If member is None, sends the message to the author of the command.
24
+ If delete is specified, deletes the message after the specified time in seconds.
25
+ """
26
+ if delete is not None and not isinstance(delete, (int, float)):
27
+ raise Exception(f'Delete parameter must be a number (seconds) or None, not {type(delete)} !')
28
+
29
+ member_to_send = ctx.author if member is None else ctx.channel.guild.get_member(member)
30
+
31
+ if member_to_send is None:
32
+ raise Exception(f'Member {member} not found!')
33
+
34
+ from .._DshellParser.ast_nodes import ListNode
35
+
36
+ if embeds is None:
37
+ embeds = ListNode([])
38
+
39
+ elif isinstance(embeds, Embed):
40
+ embeds = ListNode([embeds])
41
+
42
+ else:
43
+ raise Exception(f'Embeds must be a list of Embed objects or a single Embed object, not {type(embeds)} !')
44
+
45
+ sended_message = await member_to_send.send(message, delete_after=delete, embeds=embeds)
46
+
47
+ return sended_message.id
48
+
19
49
 
20
50
  async def dshell_ban_member(ctx: Message, member: int, reason: str = MISSING):
21
51
  """
@@ -5,6 +5,7 @@ from discord.ext import commands
5
5
 
6
6
  __all__ = [
7
7
  'dshell_send_message',
8
+ 'dshell_respond_message',
8
9
  'dshell_delete_message',
9
10
  'dshell_purge_message',
10
11
  'dshell_edit_message',
@@ -47,6 +48,32 @@ async def dshell_send_message(ctx: Message, message=None, delete=None, channel=N
47
48
  return sended_message.id
48
49
 
49
50
 
51
+ async def dshell_respond_message(ctx: Message, message=None, delete=None, embeds=None):
52
+ """
53
+ Responds to a message on Discord
54
+ """
55
+ if delete is not None and not isinstance(delete, (int, float)):
56
+ raise Exception(f'Delete parameter must be a number (seconds) or None, not {type(delete)} !')
57
+
58
+ respond_message = ctx if message is None else ctx.channel.get_partial_message(message) # builds a reference to the message (even if it doesn't exist)
59
+
60
+ from .._DshellParser.ast_nodes import ListNode
61
+
62
+ if embeds is None:
63
+ embeds = ListNode([])
64
+
65
+ elif isinstance(embeds, Embed):
66
+ embeds = ListNode([embeds])
67
+
68
+ else:
69
+ raise Exception(f'Embeds must be a list of Embed objects or a single Embed object, not {type(embeds)} !')
70
+
71
+ sended_message = await ctx.reply(respond_message,
72
+ delete_after=delete,
73
+ embeds=embeds)
74
+
75
+ return sended_message.id
76
+
50
77
  async def dshell_delete_message(ctx: Message, message=None, reason=None, delay=0):
51
78
  """
52
79
  Deletes a message
@@ -426,7 +426,7 @@ class ParamNode(ASTNode):
426
426
  self.body = body
427
427
 
428
428
  def __repr__(self):
429
- return f"<PARAM> - {self.name} *- {self.body}"
429
+ return f"<PARAM> - {self.body}"
430
430
 
431
431
  def to_dict(self):
432
432
  """
@@ -435,7 +435,6 @@ class ParamNode(ASTNode):
435
435
  """
436
436
  return {
437
437
  "type": "ParamNode",
438
- "name": self.name.to_dict(),
439
438
  "body": [token.to_dict() for token in self.body]
440
439
  }
441
440
 
@@ -28,6 +28,8 @@ dshell_commands: dict[str, Callable] = {
28
28
  "gp": dshell_get_pastbin, # get pastbin
29
29
 
30
30
  "sm": dshell_send_message, # send message
31
+ "spm": dshell_send_private_message, # send private message
32
+ "srm": dshell_respond_message, # respond to a message
31
33
  "dm": dshell_delete_message,
32
34
  "pm": dshell_purge_message,
33
35
  "em": dshell_edit_message, # edit message
@@ -37,6 +39,15 @@ dshell_commands: dict[str, Callable] = {
37
39
  "dc": dshell_delete_channel, # delete channel
38
40
  "dcs": dshell_delete_channels, # delete several channels by name or regex
39
41
 
42
+ "gc": dshell_get_channel, # get channel
43
+ "gcs": dshell_get_channels, # get channels by name or regex
44
+ "gccs": dshell_get_channels_in_category, # get channels in category
45
+
46
+ "ct": dshell_create_thread_message, # create thread
47
+ "dt": dshell_delete_thread, # delete thread
48
+ "gt": dshell_get_thread, # get thread
49
+ "et": dshell_edit_thread, # edit thread
50
+
40
51
  "bm": dshell_ban_member, # ban member
41
52
  "um": dshell_unban_member, # unban member
42
53
  "km": dshell_kick_member, # kick member
@@ -59,8 +70,8 @@ dshell_commands: dict[str, Callable] = {
59
70
 
60
71
  "ar": dshell_add_reactions, # add reactions to a message
61
72
  "rr": dshell_remove_reactions, # remove reactions from a message
62
- "cmr": dshell_clear_message_reactions,
63
- "cor": dshell_clear_one_reactions
73
+ "cmr": dshell_clear_message_reactions, # clear reactions from a message
74
+ "cor": dshell_clear_one_reactions , # clear one reaction from a message
64
75
 
65
76
  }
66
77
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 0.2.8.2
3
+ Version: 0.2.9.1
4
4
  Summary: A Discord bot interpreter for creating custom commands and automations.
5
5
  Home-page: https://github.com/BOXERRMD/Dshell_Interpreter
6
6
  Author: Chronos
@@ -1,22 +1,22 @@
1
1
  Dshell/__init__.py,sha256=pGd94FPy8kVXH_jH566HhApQPhbPfMPnZXzH_0dPWh0,93
2
2
  Dshell/_utils.py,sha256=PJ3fwn8IMqUMnW9oTwfr9v4--rzHIhhLQoVVqjwjoJU,23
3
3
  Dshell/DISCORD_COMMANDS/__init__.py,sha256=_oo_aMEju4gZg-MIbF8bKMVM6CWAF0AO9DxAlemaXMw,149
4
- Dshell/DISCORD_COMMANDS/dshell_channel.py,sha256=2qnbI2tUu5sowJVOVkY4p-l6Gu-5Gw9BEP3MItScvV8,8939
5
- Dshell/DISCORD_COMMANDS/dshell_member.py,sha256=L3Ud4nza_55n9R02kfL-iNK9ybBczx6SDkccUTWxv3s,7646
6
- Dshell/DISCORD_COMMANDS/dshell_message.py,sha256=SvX9I4nYMWm8ACE56QJBM5yEiZoXIKbTLkIOyrENd5o,6253
4
+ Dshell/DISCORD_COMMANDS/dshell_channel.py,sha256=kjSTJnTTXHprCURESlO_62jv3Yu832lUELJi47PyWdo,18538
5
+ Dshell/DISCORD_COMMANDS/dshell_member.py,sha256=CKlE9oZqI7D986uSgyRuKWJMrJD0m5BveLtzwxRtFxY,8840
6
+ Dshell/DISCORD_COMMANDS/dshell_message.py,sha256=pu5IUQH8wfteFUL0mO4Q9xEojKbKkticV-h8zrgpco8,7277
7
7
  Dshell/DISCORD_COMMANDS/dshell_pastbin.py,sha256=TkWFGRRTvhhJgvwkDFx9Fz4UM2UUFwxyq0laMVx0mUk,881
8
8
  Dshell/DISCORD_COMMANDS/dshell_role.py,sha256=fotsYWGHebgIx157q-zRbcCd90Y7jIuKCZ8udQoEzSU,4970
9
9
  Dshell/_DshellInterpreteur/__init__.py,sha256=xy5-J-R3YmY99JF3NBHTRRLsComFxpjnCA5xacISctU,35
10
10
  Dshell/_DshellInterpreteur/dshell_interpreter.py,sha256=sYQ9qIVjRedwkfITEeVAFN0RdHjiY7RGO6z0j4D7eno,23072
11
11
  Dshell/_DshellParser/__init__.py,sha256=ONDfhZMvClqP_6tE8SLjp-cf3pXL-auQYnfYRrHZxC4,56
12
- Dshell/_DshellParser/ast_nodes.py,sha256=2qwL_M0ELPia6L6gqwgV5hqprvyuo97cx3Zk2dVz09U,15341
12
+ Dshell/_DshellParser/ast_nodes.py,sha256=heOMQzAchQ8UroQaMSfU_6SYEXw-nme0jGcoVkCXPUs,15284
13
13
  Dshell/_DshellParser/dshell_parser.py,sha256=RxS5GgmTel10pH9HII0X_8XZnVyIQGd9ThZZcZDpEqc,15545
14
14
  Dshell/_DshellTokenizer/__init__.py,sha256=LIQSRhDx2B9pmPx5ADMwwD0Xr9ybneVLhHH8qrJWw_s,172
15
- Dshell/_DshellTokenizer/dshell_keywords.py,sha256=l8PZhSXLhFHpi8RRoBRm2NRvAyA_NoONw0vRU4bw3t0,5058
15
+ Dshell/_DshellTokenizer/dshell_keywords.py,sha256=yBTXKBCb7NZa-DGDeeyIZrl_CS1Y4WCmwshUdBHQhlo,5642
16
16
  Dshell/_DshellTokenizer/dshell_token_type.py,sha256=gYIb2XN2YcgeRgmar_rBDS5CGmwfmxihu8mOW_d6lbE,1533
17
17
  Dshell/_DshellTokenizer/dshell_tokenizer.py,sha256=LZGs4Ytuyx9Galazqtz32lS4Mmu9yZya1B7AzFQAQOk,7150
18
- dshellinterpreter-0.2.8.2.dist-info/licenses/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
19
- dshellinterpreter-0.2.8.2.dist-info/METADATA,sha256=IPexhINATJKbgpDcPbkvhsTeIL0gmPSHAKI2FLm8d0k,1122
20
- dshellinterpreter-0.2.8.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- dshellinterpreter-0.2.8.2.dist-info/top_level.txt,sha256=B4CMhtmchGwPQJLuqUy0GhRG-0cUGxKL4GqEbCiB_vE,7
22
- dshellinterpreter-0.2.8.2.dist-info/RECORD,,
18
+ dshellinterpreter-0.2.9.1.dist-info/licenses/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
19
+ dshellinterpreter-0.2.9.1.dist-info/METADATA,sha256=UuWw60cLp5BQu4oyfSI5gBpCg1FOuILbcNwDeLTYO6U,1122
20
+ dshellinterpreter-0.2.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ dshellinterpreter-0.2.9.1.dist-info/top_level.txt,sha256=B4CMhtmchGwPQJLuqUy0GhRG-0cUGxKL4GqEbCiB_vE,7
22
+ dshellinterpreter-0.2.9.1.dist-info/RECORD,,