loopbot-discord-sdk 1.0.0__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.
- loopbot/__init__.py +60 -0
- loopbot/bot.py +584 -0
- loopbot/builders/__init__.py +30 -0
- loopbot/builders/action_row.py +40 -0
- loopbot/builders/button.py +58 -0
- loopbot/builders/container.py +61 -0
- loopbot/builders/embed.py +95 -0
- loopbot/builders/file.py +33 -0
- loopbot/builders/media_gallery.py +36 -0
- loopbot/builders/modal.py +67 -0
- loopbot/builders/section.py +52 -0
- loopbot/builders/select_menu.py +63 -0
- loopbot/builders/separator.py +31 -0
- loopbot/builders/text_display.py +24 -0
- loopbot/client.py +805 -0
- loopbot/context/__init__.py +17 -0
- loopbot/context/base.py +263 -0
- loopbot/context/button.py +28 -0
- loopbot/context/command.py +93 -0
- loopbot/context/modal.py +46 -0
- loopbot/context/select.py +34 -0
- loopbot/types.py +76 -0
- loopbot_discord_sdk-1.0.0.dist-info/METADATA +434 -0
- loopbot_discord_sdk-1.0.0.dist-info/RECORD +26 -0
- loopbot_discord_sdk-1.0.0.dist-info/WHEEL +5 -0
- loopbot_discord_sdk-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Context classes for handling interactions
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .base import BaseContext
|
|
6
|
+
from .command import CommandContext
|
|
7
|
+
from .button import ButtonContext
|
|
8
|
+
from .modal import ModalContext
|
|
9
|
+
from .select import SelectContext
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"BaseContext",
|
|
13
|
+
"CommandContext",
|
|
14
|
+
"ButtonContext",
|
|
15
|
+
"ModalContext",
|
|
16
|
+
"SelectContext",
|
|
17
|
+
]
|
loopbot/context/base.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base Context for all interaction types
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
from ..types import Interaction, InteractionResponseType, DiscordUser, DiscordMember
|
|
8
|
+
from ..builders.embed import EmbedBuilder
|
|
9
|
+
from ..builders.action_row import ActionRowBuilder
|
|
10
|
+
from ..builders.modal import ModalBuilder
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseContext:
|
|
14
|
+
"""Base context for handling Discord interactions"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
interaction: Dict[str, Any],
|
|
19
|
+
client: Any,
|
|
20
|
+
application_id: str,
|
|
21
|
+
):
|
|
22
|
+
self._interaction = interaction
|
|
23
|
+
self._client = client
|
|
24
|
+
self._application_id = application_id
|
|
25
|
+
self._response: Optional[Dict[str, Any]] = None
|
|
26
|
+
self._deferred = False
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def interaction_id(self) -> str:
|
|
30
|
+
return self._interaction.get("id", "")
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def token(self) -> str:
|
|
34
|
+
return self._interaction.get("token", "")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def guild_id(self) -> Optional[str]:
|
|
38
|
+
return self._interaction.get("guild_id")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def channel_id(self) -> Optional[str]:
|
|
42
|
+
return self._interaction.get("channel_id")
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def user(self) -> Optional[Dict[str, Any]]:
|
|
46
|
+
"""Get the user who triggered the interaction"""
|
|
47
|
+
member = self._interaction.get("member")
|
|
48
|
+
if member:
|
|
49
|
+
return member.get("user")
|
|
50
|
+
return self._interaction.get("user")
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def user_id(self) -> Optional[str]:
|
|
54
|
+
user = self.user
|
|
55
|
+
return user.get("id") if user else None
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def username(self) -> Optional[str]:
|
|
59
|
+
user = self.user
|
|
60
|
+
return user.get("username") if user else None
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def member(self) -> Optional[Dict[str, Any]]:
|
|
64
|
+
return self._interaction.get("member")
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def locale(self) -> Optional[str]:
|
|
68
|
+
return self._interaction.get("locale")
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def response(self) -> Optional[Dict[str, Any]]:
|
|
72
|
+
return self._response
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def is_deferred(self) -> bool:
|
|
76
|
+
return self._deferred
|
|
77
|
+
|
|
78
|
+
def reply(
|
|
79
|
+
self,
|
|
80
|
+
content: Optional[str] = None,
|
|
81
|
+
embeds: Optional[List[Union[Dict[str, Any], EmbedBuilder]]] = None,
|
|
82
|
+
components: Optional[List[Union[Dict[str, Any], ActionRowBuilder]]] = None,
|
|
83
|
+
ephemeral: bool = False,
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Reply to the interaction"""
|
|
86
|
+
data: Dict[str, Any] = {}
|
|
87
|
+
|
|
88
|
+
if content:
|
|
89
|
+
data["content"] = content
|
|
90
|
+
|
|
91
|
+
if embeds:
|
|
92
|
+
data["embeds"] = [
|
|
93
|
+
e.to_dict() if isinstance(e, EmbedBuilder) else e
|
|
94
|
+
for e in embeds
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
if components:
|
|
98
|
+
data["components"] = [
|
|
99
|
+
c.to_dict() if isinstance(c, ActionRowBuilder) else c
|
|
100
|
+
for c in components
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
if ephemeral:
|
|
104
|
+
data["flags"] = 64
|
|
105
|
+
|
|
106
|
+
self._response = {
|
|
107
|
+
"type": InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
|
|
108
|
+
"data": data,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def reply_text(self, content: str, ephemeral: bool = False) -> None:
|
|
112
|
+
"""Reply with simple text"""
|
|
113
|
+
self.reply(content=content, ephemeral=ephemeral)
|
|
114
|
+
|
|
115
|
+
def reply_with_components(
|
|
116
|
+
self,
|
|
117
|
+
components: List[Any],
|
|
118
|
+
ephemeral: bool = False,
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Reply with Components V2 (Container, MediaGallery, etc.)"""
|
|
121
|
+
data: Dict[str, Any] = {
|
|
122
|
+
"components": [
|
|
123
|
+
c.to_dict() if hasattr(c, "to_dict") else c
|
|
124
|
+
for c in components
|
|
125
|
+
],
|
|
126
|
+
"flags": 32768, # IS_COMPONENTS_V2
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if ephemeral:
|
|
130
|
+
data["flags"] |= 64
|
|
131
|
+
|
|
132
|
+
self._response = {
|
|
133
|
+
"type": InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
|
|
134
|
+
"data": data,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
def update(
|
|
138
|
+
self,
|
|
139
|
+
content: Optional[str] = None,
|
|
140
|
+
embeds: Optional[List[Union[Dict[str, Any], EmbedBuilder]]] = None,
|
|
141
|
+
components: Optional[List[Union[Dict[str, Any], ActionRowBuilder]]] = None,
|
|
142
|
+
) -> None:
|
|
143
|
+
"""Update the original message"""
|
|
144
|
+
data: Dict[str, Any] = {}
|
|
145
|
+
|
|
146
|
+
if content is not None:
|
|
147
|
+
data["content"] = content
|
|
148
|
+
|
|
149
|
+
if embeds:
|
|
150
|
+
data["embeds"] = [
|
|
151
|
+
e.to_dict() if isinstance(e, EmbedBuilder) else e
|
|
152
|
+
for e in embeds
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
if components:
|
|
156
|
+
data["components"] = [
|
|
157
|
+
c.to_dict() if isinstance(c, ActionRowBuilder) else c
|
|
158
|
+
for c in components
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
self._response = {
|
|
162
|
+
"type": InteractionResponseType.UPDATE_MESSAGE,
|
|
163
|
+
"data": data,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
def update_with_components(self, components: List[Any]) -> None:
|
|
167
|
+
"""Update the original message with Components V2"""
|
|
168
|
+
self._response = {
|
|
169
|
+
"type": InteractionResponseType.UPDATE_MESSAGE,
|
|
170
|
+
"data": {
|
|
171
|
+
"components": [
|
|
172
|
+
c.to_dict() if hasattr(c, "to_dict") else c
|
|
173
|
+
for c in components
|
|
174
|
+
],
|
|
175
|
+
"flags": 32768, # IS_COMPONENTS_V2
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
def defer(self, ephemeral: bool = False) -> None:
|
|
180
|
+
"""Defer the response (show 'thinking...')"""
|
|
181
|
+
self._deferred = True
|
|
182
|
+
self._response = {
|
|
183
|
+
"type": InteractionResponseType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
|
|
184
|
+
"data": {"flags": 64 if ephemeral else 0},
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
def defer_update(self) -> None:
|
|
188
|
+
"""Defer the update (acknowledge without visible loading)"""
|
|
189
|
+
self._deferred = True
|
|
190
|
+
self._response = {
|
|
191
|
+
"type": InteractionResponseType.DEFERRED_UPDATE_MESSAGE,
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
def show_modal(self, modal: ModalBuilder) -> None:
|
|
195
|
+
"""Show a modal to the user"""
|
|
196
|
+
self._response = {
|
|
197
|
+
"type": InteractionResponseType.MODAL,
|
|
198
|
+
"data": modal.to_dict(),
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async def follow_up(
|
|
202
|
+
self,
|
|
203
|
+
content: Optional[str] = None,
|
|
204
|
+
embeds: Optional[List[Union[Dict[str, Any], EmbedBuilder]]] = None,
|
|
205
|
+
components: Optional[List[Union[Dict[str, Any], ActionRowBuilder]]] = None,
|
|
206
|
+
ephemeral: bool = False,
|
|
207
|
+
) -> Dict[str, Any]:
|
|
208
|
+
"""Send a follow-up message"""
|
|
209
|
+
data: Dict[str, Any] = {}
|
|
210
|
+
|
|
211
|
+
if content:
|
|
212
|
+
data["content"] = content
|
|
213
|
+
|
|
214
|
+
if embeds:
|
|
215
|
+
data["embeds"] = [
|
|
216
|
+
e.to_dict() if isinstance(e, EmbedBuilder) else e
|
|
217
|
+
for e in embeds
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
if components:
|
|
221
|
+
data["components"] = [
|
|
222
|
+
c.to_dict() if isinstance(c, ActionRowBuilder) else c
|
|
223
|
+
for c in components
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
if ephemeral:
|
|
227
|
+
data["flags"] = 64
|
|
228
|
+
|
|
229
|
+
return await self._client.follow_up(
|
|
230
|
+
self._application_id,
|
|
231
|
+
self.token,
|
|
232
|
+
data,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
async def edit_reply(
|
|
236
|
+
self,
|
|
237
|
+
content: Optional[str] = None,
|
|
238
|
+
embeds: Optional[List[Union[Dict[str, Any], EmbedBuilder]]] = None,
|
|
239
|
+
components: Optional[List[Union[Dict[str, Any], ActionRowBuilder]]] = None,
|
|
240
|
+
) -> None:
|
|
241
|
+
"""Edit the original response"""
|
|
242
|
+
data: Dict[str, Any] = {}
|
|
243
|
+
|
|
244
|
+
if content is not None:
|
|
245
|
+
data["content"] = content
|
|
246
|
+
|
|
247
|
+
if embeds:
|
|
248
|
+
data["embeds"] = [
|
|
249
|
+
e.to_dict() if isinstance(e, EmbedBuilder) else e
|
|
250
|
+
for e in embeds
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
if components:
|
|
254
|
+
data["components"] = [
|
|
255
|
+
c.to_dict() if isinstance(c, ActionRowBuilder) else c
|
|
256
|
+
for c in components
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
await self._client.edit_original(
|
|
260
|
+
self._application_id,
|
|
261
|
+
self.token,
|
|
262
|
+
data,
|
|
263
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Button Context for button interactions
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from .base import BaseContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ButtonContext(BaseContext):
|
|
11
|
+
"""Context for handling button interactions"""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def custom_id(self) -> str:
|
|
15
|
+
"""Get the button custom ID"""
|
|
16
|
+
data = self._interaction.get("data", {})
|
|
17
|
+
return data.get("custom_id", "")
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def message(self) -> Optional[Dict[str, Any]]:
|
|
21
|
+
"""Get the message the button was attached to"""
|
|
22
|
+
return self._interaction.get("message")
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def message_id(self) -> Optional[str]:
|
|
26
|
+
"""Get the message ID"""
|
|
27
|
+
message = self.message
|
|
28
|
+
return message.get("id") if message else None
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command Context for slash commands
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from .base import BaseContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CommandContext(BaseContext):
|
|
11
|
+
"""Context for handling slash command interactions"""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def command_name(self) -> str:
|
|
15
|
+
"""Get the command name"""
|
|
16
|
+
data = self._interaction.get("data", {})
|
|
17
|
+
return data.get("name", "")
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def options(self) -> Dict[str, Any]:
|
|
21
|
+
"""Get command options as a dict"""
|
|
22
|
+
data = self._interaction.get("data", {})
|
|
23
|
+
options = data.get("options", [])
|
|
24
|
+
return self._parse_options(options)
|
|
25
|
+
|
|
26
|
+
def _parse_options(self, options: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
27
|
+
"""Parse options list into dict"""
|
|
28
|
+
result: Dict[str, Any] = {}
|
|
29
|
+
for opt in options:
|
|
30
|
+
name = opt.get("name", "")
|
|
31
|
+
value = opt.get("value")
|
|
32
|
+
|
|
33
|
+
# Handle subcommands/groups
|
|
34
|
+
if opt.get("options"):
|
|
35
|
+
result[name] = self._parse_options(opt["options"])
|
|
36
|
+
else:
|
|
37
|
+
result[name] = value
|
|
38
|
+
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
def get_option(
|
|
42
|
+
self,
|
|
43
|
+
name: str,
|
|
44
|
+
default: Any = None,
|
|
45
|
+
) -> Any:
|
|
46
|
+
"""Get a specific option value"""
|
|
47
|
+
return self.options.get(name, default)
|
|
48
|
+
|
|
49
|
+
def get_string(self, name: str, default: str = "") -> str:
|
|
50
|
+
"""Get a string option"""
|
|
51
|
+
return str(self.get_option(name, default))
|
|
52
|
+
|
|
53
|
+
def get_int(self, name: str, default: int = 0) -> int:
|
|
54
|
+
"""Get an integer option"""
|
|
55
|
+
value = self.get_option(name, default)
|
|
56
|
+
return int(value) if value is not None else default
|
|
57
|
+
|
|
58
|
+
def get_bool(self, name: str, default: bool = False) -> bool:
|
|
59
|
+
"""Get a boolean option"""
|
|
60
|
+
return bool(self.get_option(name, default))
|
|
61
|
+
|
|
62
|
+
def get_user(self, name: str) -> Optional[Dict[str, Any]]:
|
|
63
|
+
"""Get a user option from resolved data"""
|
|
64
|
+
user_id = self.get_option(name)
|
|
65
|
+
if not user_id:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
data = self._interaction.get("data", {})
|
|
69
|
+
resolved = data.get("resolved", {})
|
|
70
|
+
users = resolved.get("users", {})
|
|
71
|
+
return users.get(user_id)
|
|
72
|
+
|
|
73
|
+
def get_channel(self, name: str) -> Optional[Dict[str, Any]]:
|
|
74
|
+
"""Get a channel option from resolved data"""
|
|
75
|
+
channel_id = self.get_option(name)
|
|
76
|
+
if not channel_id:
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
data = self._interaction.get("data", {})
|
|
80
|
+
resolved = data.get("resolved", {})
|
|
81
|
+
channels = resolved.get("channels", {})
|
|
82
|
+
return channels.get(channel_id)
|
|
83
|
+
|
|
84
|
+
def get_role(self, name: str) -> Optional[Dict[str, Any]]:
|
|
85
|
+
"""Get a role option from resolved data"""
|
|
86
|
+
role_id = self.get_option(name)
|
|
87
|
+
if not role_id:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
data = self._interaction.get("data", {})
|
|
91
|
+
resolved = data.get("resolved", {})
|
|
92
|
+
roles = resolved.get("roles", {})
|
|
93
|
+
return roles.get(role_id)
|
loopbot/context/modal.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Modal Context for modal submit interactions
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from .base import BaseContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ModalContext(BaseContext):
|
|
11
|
+
"""Context for handling modal submit interactions"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
|
14
|
+
super().__init__(*args, **kwargs)
|
|
15
|
+
self._fields: Dict[str, str] = self._parse_fields()
|
|
16
|
+
|
|
17
|
+
def _parse_fields(self) -> Dict[str, str]:
|
|
18
|
+
"""Parse modal fields from interaction data"""
|
|
19
|
+
fields: Dict[str, str] = {}
|
|
20
|
+
data = self._interaction.get("data", {})
|
|
21
|
+
components = data.get("components", [])
|
|
22
|
+
|
|
23
|
+
for row in components:
|
|
24
|
+
row_components = row.get("components", [])
|
|
25
|
+
for component in row_components:
|
|
26
|
+
custom_id = component.get("custom_id", "")
|
|
27
|
+
value = component.get("value", "")
|
|
28
|
+
if custom_id:
|
|
29
|
+
fields[custom_id] = value
|
|
30
|
+
|
|
31
|
+
return fields
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def custom_id(self) -> str:
|
|
35
|
+
"""Get the modal custom ID"""
|
|
36
|
+
data = self._interaction.get("data", {})
|
|
37
|
+
return data.get("custom_id", "")
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def fields(self) -> Dict[str, str]:
|
|
41
|
+
"""Get all modal fields as dict"""
|
|
42
|
+
return self._fields
|
|
43
|
+
|
|
44
|
+
def get_field(self, custom_id: str, default: str = "") -> str:
|
|
45
|
+
"""Get a specific field value"""
|
|
46
|
+
return self._fields.get(custom_id, default)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Select Context for select menu interactions
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from .base import BaseContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SelectContext(BaseContext):
|
|
11
|
+
"""Context for handling select menu interactions"""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def custom_id(self) -> str:
|
|
15
|
+
"""Get the select menu custom ID"""
|
|
16
|
+
data = self._interaction.get("data", {})
|
|
17
|
+
return data.get("custom_id", "")
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def values(self) -> List[str]:
|
|
21
|
+
"""Get selected values"""
|
|
22
|
+
data = self._interaction.get("data", {})
|
|
23
|
+
return data.get("values", [])
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def message(self) -> Optional[Dict[str, Any]]:
|
|
27
|
+
"""Get the message the select was attached to"""
|
|
28
|
+
return self._interaction.get("message")
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def message_id(self) -> Optional[str]:
|
|
32
|
+
"""Get the message ID"""
|
|
33
|
+
message = self.message
|
|
34
|
+
return message.get("id") if message else None
|
loopbot/types.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Types and enums for the Loop Discord SDK
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import IntEnum
|
|
6
|
+
from typing import Any, Dict, List, Optional, TypedDict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class InteractionType(IntEnum):
|
|
10
|
+
PING = 1
|
|
11
|
+
APPLICATION_COMMAND = 2
|
|
12
|
+
MESSAGE_COMPONENT = 3
|
|
13
|
+
APPLICATION_COMMAND_AUTOCOMPLETE = 4
|
|
14
|
+
MODAL_SUBMIT = 5
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class InteractionResponseType(IntEnum):
|
|
18
|
+
PONG = 1
|
|
19
|
+
CHANNEL_MESSAGE_WITH_SOURCE = 4
|
|
20
|
+
DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE = 5
|
|
21
|
+
DEFERRED_UPDATE_MESSAGE = 6
|
|
22
|
+
UPDATE_MESSAGE = 7
|
|
23
|
+
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8
|
|
24
|
+
MODAL = 9
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DiscordUser(TypedDict, total=False):
|
|
28
|
+
id: str
|
|
29
|
+
username: str
|
|
30
|
+
discriminator: str
|
|
31
|
+
avatar: Optional[str]
|
|
32
|
+
bot: bool
|
|
33
|
+
global_name: Optional[str]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DiscordMember(TypedDict, total=False):
|
|
37
|
+
user: DiscordUser
|
|
38
|
+
nick: Optional[str]
|
|
39
|
+
roles: List[str]
|
|
40
|
+
joined_at: str
|
|
41
|
+
permissions: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class DiscordMessage(TypedDict, total=False):
|
|
45
|
+
id: str
|
|
46
|
+
channel_id: str
|
|
47
|
+
content: str
|
|
48
|
+
author: DiscordUser
|
|
49
|
+
embeds: List[Dict[str, Any]]
|
|
50
|
+
components: List[Dict[str, Any]]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class InteractionData(TypedDict, total=False):
|
|
54
|
+
id: str
|
|
55
|
+
name: str
|
|
56
|
+
type: int
|
|
57
|
+
options: List[Dict[str, Any]]
|
|
58
|
+
custom_id: str
|
|
59
|
+
component_type: int
|
|
60
|
+
values: List[str]
|
|
61
|
+
components: List[Dict[str, Any]]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Interaction(TypedDict, total=False):
|
|
65
|
+
id: str
|
|
66
|
+
application_id: str
|
|
67
|
+
type: int
|
|
68
|
+
data: InteractionData
|
|
69
|
+
guild_id: str
|
|
70
|
+
channel_id: str
|
|
71
|
+
member: DiscordMember
|
|
72
|
+
user: DiscordUser
|
|
73
|
+
token: str
|
|
74
|
+
version: int
|
|
75
|
+
message: DiscordMessage
|
|
76
|
+
locale: str
|