scurry-kit 0.2__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.
- scurry_kit/__init__.py +9 -0
- scurry_kit/addons/__init__.py +9 -0
- scurry_kit/addons/cache/__init__.py +13 -0
- scurry_kit/addons/cache/bot_emojis.py +34 -0
- scurry_kit/addons/cache/channel.py +113 -0
- scurry_kit/addons/cache/guild_emojis.py +92 -0
- scurry_kit/addons/cache/role.py +108 -0
- scurry_kit/addons/component_builder.py +290 -0
- scurry_kit/addons/embed_builder.py +64 -0
- scurry_kit/addons/events.py +62 -0
- scurry_kit/addons/interaction.py +253 -0
- scurry_kit/addons/prefix.py +86 -0
- scurry_kit/client.py +235 -0
- scurry_kit-0.2.dist-info/METADATA +53 -0
- scurry_kit-0.2.dist-info/RECORD +18 -0
- scurry_kit-0.2.dist-info/WHEEL +5 -0
- scurry_kit-0.2.dist-info/licenses/LICENSE +16 -0
- scurry_kit-0.2.dist-info/top_level.txt +1 -0
scurry_kit/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# easybot/addons/cache
|
|
2
|
+
|
|
3
|
+
from .bot_emojis import BotEmojisCacheAddon
|
|
4
|
+
from .channel import GuildChannelCacheAddon
|
|
5
|
+
from .guild_emojis import GuildEmojiCacheAddon
|
|
6
|
+
from .role import RoleCacheAddon
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'BotEmojisCacheAddon',
|
|
10
|
+
'GuildChannelCacheAddon',
|
|
11
|
+
'GuildEmojiCacheAddon',
|
|
12
|
+
'RoleCacheAddon'
|
|
13
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from scurrypy import (
|
|
2
|
+
Addon,
|
|
3
|
+
Client,
|
|
4
|
+
EmojiModel
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
class BotEmojisCacheAddon(Addon):
|
|
8
|
+
"""Defines caching bot emojis and lookup."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, client: Client):
|
|
11
|
+
self.bot = client
|
|
12
|
+
self.emojis: dict[str, EmojiModel] = {} # index by unique name
|
|
13
|
+
client.addons.add(self)
|
|
14
|
+
|
|
15
|
+
def setup(self):
|
|
16
|
+
self.bot.add_startup_hook(self.load_bot_emojis)
|
|
17
|
+
|
|
18
|
+
async def load_bot_emojis(self):
|
|
19
|
+
"""Fetch all bot's emojis and add them to the cache."""
|
|
20
|
+
emojis = await self.bot.bot_emoji().fetch_all()
|
|
21
|
+
|
|
22
|
+
for emoji in emojis:
|
|
23
|
+
self.emojis[emoji.name] = emoji
|
|
24
|
+
|
|
25
|
+
def get_emoji(self, name: str):
|
|
26
|
+
"""Get an emoji from the cache.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
name (str): name of the emoji
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
(EmojiModel | None): the emoji object if found else None
|
|
33
|
+
"""
|
|
34
|
+
return self.emojis.get(name)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from scurrypy import (
|
|
2
|
+
Addon,
|
|
3
|
+
Client,
|
|
4
|
+
ChannelModel,
|
|
5
|
+
GuildCreateEvent, GuildDeleteEvent,
|
|
6
|
+
GuildChannelCreateEvent, GuildChannelUpdateEvent, GuildChannelDeleteEvent
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
class GuildChannelCacheAddon(Addon):
|
|
10
|
+
"""Defines caching channels and lookup."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client: Client):
|
|
13
|
+
self.bot = client
|
|
14
|
+
|
|
15
|
+
self.channels: dict[int, dict[int, ChannelModel]] = {} # stores OBJECTS
|
|
16
|
+
self.channel_index: dict[int, ChannelModel] = {} # stores REFERENCES
|
|
17
|
+
|
|
18
|
+
client.addons.add(self)
|
|
19
|
+
|
|
20
|
+
def setup(self):
|
|
21
|
+
self.bot.add_startup_hook(self.on_startup)
|
|
22
|
+
|
|
23
|
+
def on_startup(self):
|
|
24
|
+
self.bot.add_event_listener('GUILD_CREATE', self.on_guild_create)
|
|
25
|
+
self.bot.add_event_listener('GUILD_DELETE', self.on_guild_delete)
|
|
26
|
+
|
|
27
|
+
self.bot.add_event_listener('CHANNEL_CREATE', self.on_channel_create)
|
|
28
|
+
self.bot.add_event_listener('CHANNEL_UPDATE', self.on_channel_update)
|
|
29
|
+
self.bot.add_event_listener('CHANNEL_DELETE', self.on_channel_delete)
|
|
30
|
+
|
|
31
|
+
def on_guild_create(self, event: GuildCreateEvent):
|
|
32
|
+
"""Append new guild channels to cache. Also add channels to index.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
event (GuildCreateEvent): the GUILD_CREATE event
|
|
36
|
+
"""
|
|
37
|
+
guild_dict = self.channels.setdefault(event.id, {})
|
|
38
|
+
|
|
39
|
+
for ch in event.channels:
|
|
40
|
+
guild_dict[ch.id] = ch
|
|
41
|
+
self.channel_index[ch.id] = ch
|
|
42
|
+
|
|
43
|
+
def on_guild_delete(self, event: GuildDeleteEvent):
|
|
44
|
+
"""Remove guild channels from cache. Also remove channels from index
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
event (GuildDeleteEvent): the GUILD_DELETE event
|
|
48
|
+
"""
|
|
49
|
+
removed_channels = self.channels.pop(event.id, {})
|
|
50
|
+
|
|
51
|
+
for ch in removed_channels.values():
|
|
52
|
+
self.channel_index.pop(ch.id, None)
|
|
53
|
+
|
|
54
|
+
def on_channel_create(self, event: GuildChannelCreateEvent):
|
|
55
|
+
"""Append channel to guild key. Also append channel to index.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
event (GuildChannelCreateEvent): the CHANNEL_CREATE event
|
|
59
|
+
"""
|
|
60
|
+
model = ChannelModel.from_dict(event.raw)
|
|
61
|
+
guild_dict = self.channels.setdefault(event.guild_id, {})
|
|
62
|
+
|
|
63
|
+
guild_dict[event.id] = model
|
|
64
|
+
self.channel_index[event.id] = model
|
|
65
|
+
|
|
66
|
+
def on_channel_update(self, event: GuildChannelUpdateEvent):
|
|
67
|
+
"""Replace channel in guild key. Also replace channel in index.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
event (GuildChannelUpdateEvent): the CHANNEL_UPDATE event
|
|
71
|
+
"""
|
|
72
|
+
model = ChannelModel.from_dict(event.raw)
|
|
73
|
+
guild_dict = self.channels.setdefault(event.guild_id, {})
|
|
74
|
+
|
|
75
|
+
guild_dict[event.id] = model
|
|
76
|
+
self.channel_index[event.id] = model
|
|
77
|
+
|
|
78
|
+
def on_channel_delete(self, event: GuildChannelDeleteEvent):
|
|
79
|
+
"""Remove channel from guild key. Also remove channel from index.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
event (GuildChannelDeleteEvent): the CHANNEL_DELETE event
|
|
83
|
+
"""
|
|
84
|
+
model = self.channel_index.pop(event.id, None)
|
|
85
|
+
if model:
|
|
86
|
+
self.channels.get(event.guild_id, {}).pop(event.id, None)
|
|
87
|
+
|
|
88
|
+
def get_channel(self, channel_id: int):
|
|
89
|
+
"""Get a channel from the cache.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
channel_id (int): ID of the channel
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
(ChannelModel | None): the channel object if found else None
|
|
96
|
+
"""
|
|
97
|
+
return self.channel_index.get(channel_id)
|
|
98
|
+
|
|
99
|
+
def put(self, channel: ChannelModel):
|
|
100
|
+
"""Put a new channel into the cache.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
channel (ChannelModel): the channel object
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
ValueError: missing `guild_id`
|
|
107
|
+
"""
|
|
108
|
+
if channel.guild_id is None:
|
|
109
|
+
raise ValueError("Cannot cache a channel without a guild_id.")
|
|
110
|
+
|
|
111
|
+
guild_dict = self.channels.setdefault(channel.guild_id, {})
|
|
112
|
+
guild_dict[channel.id] = channel
|
|
113
|
+
self.channel_index[channel.id] = channel
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from scurrypy import (
|
|
2
|
+
Addon,
|
|
3
|
+
Client,
|
|
4
|
+
Intents,
|
|
5
|
+
EmojiModel,
|
|
6
|
+
GuildCreateEvent, GuildDeleteEvent,
|
|
7
|
+
GuildEmojisUpdateEvent
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
class GuildEmojiCacheAddon(Addon):
|
|
11
|
+
"""Defines caching guild emojis and lookup.
|
|
12
|
+
|
|
13
|
+
!!! important
|
|
14
|
+
This cache requires `Intents.GUILD_EMOJIS_AND_STICKERS` to keep up-to-date.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, client: Client):
|
|
18
|
+
self.bot = client
|
|
19
|
+
|
|
20
|
+
if not Intents.has(client.intents, Intents.GUILD_EMOJIS_AND_STICKERS):
|
|
21
|
+
raise ValueError("GuildEmojiCache requires Intents.GUILD_EMOJIS_AND_STICKERS for GUILD_EMOJIS_UPDATE event.")
|
|
22
|
+
|
|
23
|
+
self.guild_emojis: dict[int, dict[int, EmojiModel]] = {} # owns emoji objects
|
|
24
|
+
self.guild_emoji_index: dict[int, EmojiModel] = {} # index by ID (reference)
|
|
25
|
+
|
|
26
|
+
client.addons.add(self)
|
|
27
|
+
|
|
28
|
+
def setup(self):
|
|
29
|
+
self.bot.add_startup_hook(self.on_startup)
|
|
30
|
+
|
|
31
|
+
def on_startup(self):
|
|
32
|
+
self.bot.add_event_listener('GUILD_CREATE', self.on_guild_create)
|
|
33
|
+
self.bot.add_event_listener('GUILD_DELETE', self.on_guild_delete)
|
|
34
|
+
|
|
35
|
+
self.bot.add_event_listener('GUILD_EMOJIS_UPDATE', self.on_emojis_update)
|
|
36
|
+
|
|
37
|
+
def on_guild_create(self, event: GuildCreateEvent):
|
|
38
|
+
"""Append new guild emojis to cache. Also add emojis to index.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
event (GuildCreateEvent): the GUILD_CREATE event
|
|
42
|
+
"""
|
|
43
|
+
guild_dict = self.guild_emojis.setdefault(event.id, {})
|
|
44
|
+
|
|
45
|
+
# event.emojis is already hydrated
|
|
46
|
+
for emoji in event.emojis:
|
|
47
|
+
guild_dict[emoji.id] = emoji
|
|
48
|
+
self.guild_emoji_index[emoji.id] = emoji
|
|
49
|
+
|
|
50
|
+
def on_guild_delete(self, event: GuildDeleteEvent):
|
|
51
|
+
"""Remove guild emojis from cache. Also remove emojis from index
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
event (GuildDeleteEvent): the GUILD_DELETE event
|
|
55
|
+
"""
|
|
56
|
+
removed = self.guild_emojis.pop(event.id, {})
|
|
57
|
+
|
|
58
|
+
for emoji in removed.values():
|
|
59
|
+
self.guild_emoji_index.pop(emoji.id, None)
|
|
60
|
+
|
|
61
|
+
def on_emojis_update(self, event: GuildEmojisUpdateEvent):
|
|
62
|
+
"""Refresh guild emojis with new list. Also refresh the index
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
event (GuildEmojisUpdateEvent): the GUILD_EMOJIS_UPDATE event
|
|
66
|
+
"""
|
|
67
|
+
guild_id = event.guild_id
|
|
68
|
+
|
|
69
|
+
# remove old emojis
|
|
70
|
+
removed = self.guild_emojis.pop(guild_id, {})
|
|
71
|
+
|
|
72
|
+
for emoji in removed.values():
|
|
73
|
+
self.guild_emoji_index.pop(emoji.id, None)
|
|
74
|
+
|
|
75
|
+
# add new emoji set (full replacement)
|
|
76
|
+
guild_dict = self.guild_emojis.setdefault(guild_id, {})
|
|
77
|
+
|
|
78
|
+
for emoji in event.emojis:
|
|
79
|
+
guild_dict[emoji.id] = emoji
|
|
80
|
+
self.guild_emoji_index[emoji.id] = emoji
|
|
81
|
+
|
|
82
|
+
def get_emoji(self, emoji_id: int):
|
|
83
|
+
"""Get an emoji from the cache.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
emoji_id (int): ID of the emoji
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
(EmojiModel | None): the Emoji object if found, else None
|
|
90
|
+
"""
|
|
91
|
+
return self.guild_emoji_index.get(emoji_id, None)
|
|
92
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from scurrypy import (
|
|
2
|
+
Addon,
|
|
3
|
+
Client,
|
|
4
|
+
RoleModel,
|
|
5
|
+
GuildCreateEvent, GuildDeleteEvent,
|
|
6
|
+
RoleCreateEvent, RoleUpdateEvent, RoleDeleteEvent
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
class RoleCacheAddon(Addon):
|
|
10
|
+
"""Defines caching guild roles and lookup."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client: Client):
|
|
13
|
+
self.bot = client
|
|
14
|
+
|
|
15
|
+
self.roles: dict[int, dict[int, RoleModel]] = {} # stores OBJECTS
|
|
16
|
+
self.role_index: dict[int, RoleModel] = {} # stores REFERENCES
|
|
17
|
+
|
|
18
|
+
client.addons.add(self)
|
|
19
|
+
|
|
20
|
+
def setup(self):
|
|
21
|
+
self.bot.add_startup_hook(self.on_startup)
|
|
22
|
+
|
|
23
|
+
def on_startup(self):
|
|
24
|
+
self.bot.add_event_listener('GUILD_CREATE', self.on_guild_create)
|
|
25
|
+
self.bot.add_event_listener('GUILD_DELETE', self.on_guild_delete)
|
|
26
|
+
|
|
27
|
+
self.bot.add_event_listener('ROLE_CREATE', self.on_role_create)
|
|
28
|
+
self.bot.add_event_listener('ROLE_UPDATE', self.on_role_update)
|
|
29
|
+
self.bot.add_event_listener('ROLE_DELETE', self.on_role_delete)
|
|
30
|
+
|
|
31
|
+
def on_guild_create(self, event: GuildCreateEvent):
|
|
32
|
+
"""Append new guild roles to cache. Also add roles to index.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
event (GuildCreateEvent): the GUILD_CREATE event
|
|
36
|
+
"""
|
|
37
|
+
guild_dict = self.roles.setdefault(event.id, {})
|
|
38
|
+
|
|
39
|
+
for role in event.roles:
|
|
40
|
+
guild_dict[role.id] = role
|
|
41
|
+
self.role_index[role.id] = role
|
|
42
|
+
|
|
43
|
+
def on_guild_delete(self, event: GuildDeleteEvent):
|
|
44
|
+
"""Remove guild roles from cache. Also remove roles from index
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
event (GuildDeleteEvent): the GUILD_DELETE event
|
|
48
|
+
"""
|
|
49
|
+
removed_roles = self.roles.pop(event.id, {})
|
|
50
|
+
|
|
51
|
+
for role in removed_roles.values():
|
|
52
|
+
self.role_index.pop(role.id, None)
|
|
53
|
+
|
|
54
|
+
def on_role_create(self, event: RoleCreateEvent):
|
|
55
|
+
"""Append role to guild key. Also append role to index.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
event (RoleCreateEvent): the ROLE_CREATE event
|
|
59
|
+
"""
|
|
60
|
+
model = RoleModel.from_dict(event.raw)
|
|
61
|
+
guild_dict = self.roles.setdefault(event.guild_id, {})
|
|
62
|
+
|
|
63
|
+
guild_dict[event.role.id] = model
|
|
64
|
+
self.role_index[event.role.id] = model
|
|
65
|
+
|
|
66
|
+
def on_role_update(self, event: RoleUpdateEvent):
|
|
67
|
+
"""Replace role in guild key. Also replace role in index.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
event (RoleUpdateEvent): the ROLE_UPDATE event
|
|
71
|
+
"""
|
|
72
|
+
model = RoleModel.from_dict(event.raw)
|
|
73
|
+
guild_dict = self.roles.setdefault(event.guild_id, {})
|
|
74
|
+
|
|
75
|
+
guild_dict[event.role.id] = model
|
|
76
|
+
self.role_index[event.role.id] = model
|
|
77
|
+
|
|
78
|
+
def on_role_delete(self, event: RoleDeleteEvent):
|
|
79
|
+
"""Remove role from guild key. Also remove role from index.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
event (RoleDeleteEvent): the ROLE_DELETE event
|
|
83
|
+
"""
|
|
84
|
+
model = self.role_index.pop(event.role_id, None)
|
|
85
|
+
if model:
|
|
86
|
+
self.roles.get(event.guild_id, {}).pop(event.role_id, None)
|
|
87
|
+
|
|
88
|
+
def get_role(self, role_id: int):
|
|
89
|
+
"""Get a role from the cache.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
role_id (int): ID of the role
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
(RoleModel | None): the role object if found else None
|
|
96
|
+
"""
|
|
97
|
+
return self.role_index.get(role_id)
|
|
98
|
+
|
|
99
|
+
def put(self, guild_id: int, role: RoleModel):
|
|
100
|
+
"""Put a new role into the cache.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
guild_id (int): guild ID of the role
|
|
104
|
+
role (RoleModel): the role object
|
|
105
|
+
"""
|
|
106
|
+
guild_dict = self.roles.setdefault(guild_id, {})
|
|
107
|
+
guild_dict[role.id] = role
|
|
108
|
+
self.role_index[role.id] = role
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
from scurrypy import (
|
|
2
|
+
Addon,
|
|
3
|
+
EmojiModel,
|
|
4
|
+
Button, ButtonStyles,
|
|
5
|
+
ActionRowChild, ActionRowPart,
|
|
6
|
+
SelectOption,
|
|
7
|
+
TextInput, TextInputStyles,
|
|
8
|
+
DefaultValue
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
class ComponentBuilder(Addon):
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def _basic_button(
|
|
15
|
+
style: int,
|
|
16
|
+
custom_id: str,
|
|
17
|
+
label: str = None,
|
|
18
|
+
emoji: str | EmojiModel = None,
|
|
19
|
+
disabled: bool = False
|
|
20
|
+
):
|
|
21
|
+
if emoji:
|
|
22
|
+
if isinstance(emoji, str):
|
|
23
|
+
emoji = EmojiModel(name=emoji)
|
|
24
|
+
elif not isinstance(emoji, EmojiModel):
|
|
25
|
+
raise TypeError(f"EasyBot.primary expects type str or EmojiModel, got {type(emoji).__name__}")
|
|
26
|
+
|
|
27
|
+
return Button(
|
|
28
|
+
style=style,
|
|
29
|
+
custom_id=custom_id,
|
|
30
|
+
label=label,
|
|
31
|
+
emoji=emoji ,
|
|
32
|
+
disabled=disabled
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def primary(
|
|
37
|
+
custom_id: str,
|
|
38
|
+
label: str = None,
|
|
39
|
+
emoji: str | EmojiModel = None,
|
|
40
|
+
disabled: bool = False
|
|
41
|
+
):
|
|
42
|
+
"""Builds a primary button
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
custom_id (str): unique button identifier
|
|
46
|
+
label (str, optional): user-facing label
|
|
47
|
+
emoji (str | EmojiModel, optional): emoji icon as str or EmojiModel if custom
|
|
48
|
+
disabled (bool, optional): Whether the button should be disabled. Defaults to False.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
(Button): the button object
|
|
52
|
+
"""
|
|
53
|
+
return ComponentBuilder._basic_button(ButtonStyles.PRIMARY, custom_id, label, emoji, disabled)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def secondary(
|
|
57
|
+
custom_id: str,
|
|
58
|
+
label: str = None,
|
|
59
|
+
emoji: str | EmojiModel = None,
|
|
60
|
+
disabled: bool = False
|
|
61
|
+
):
|
|
62
|
+
"""Builds a secondary button
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
custom_id (str): unique button identifier
|
|
66
|
+
label (str, optional): user-facing label
|
|
67
|
+
emoji (str | EmojiModel, optional): emoji icon as str or EmojiModel if custom
|
|
68
|
+
disabled (bool, optional): Whether the button should be disabled. Defaults to False.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
(Button): the button object
|
|
72
|
+
"""
|
|
73
|
+
return ComponentBuilder._basic_button(ButtonStyles.SECONDARY, custom_id, label, emoji, disabled)
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def success(
|
|
77
|
+
custom_id: str,
|
|
78
|
+
label: str = None,
|
|
79
|
+
emoji: str | EmojiModel = None,
|
|
80
|
+
disabled: bool = False
|
|
81
|
+
):
|
|
82
|
+
"""Builds a success button
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
custom_id (str): unique button identifier
|
|
86
|
+
label (str, optional): user-facing label
|
|
87
|
+
emoji (str | EmojiModel, optional): emoji icon as str or EmojiModel if custom
|
|
88
|
+
disabled (bool, optional): Whether the button should be disabled. Defaults to False.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
(Button): the button object
|
|
92
|
+
"""
|
|
93
|
+
return ComponentBuilder._basic_button(ButtonStyles.SUCCESS, custom_id, label, emoji, disabled)
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def danger(
|
|
97
|
+
custom_id: str,
|
|
98
|
+
label: str = None,
|
|
99
|
+
emoji: str | EmojiModel = None,
|
|
100
|
+
disabled: bool = False
|
|
101
|
+
):
|
|
102
|
+
"""Builds a danger button
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
custom_id (str): unique button identifier
|
|
106
|
+
label (str, optional): user-facing label
|
|
107
|
+
emoji (str | EmojiModel, optional): emoji icon as str or EmojiModel if custom
|
|
108
|
+
disabled (bool, optional): Whether the button should be disabled. Defaults to False.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
(Button): the button object
|
|
112
|
+
"""
|
|
113
|
+
return ComponentBuilder._basic_button(ButtonStyles.DANGER, custom_id, label, emoji, disabled)
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def link(
|
|
117
|
+
url: str,
|
|
118
|
+
label: str = None,
|
|
119
|
+
emoji: str | EmojiModel = None,
|
|
120
|
+
disabled: bool = False
|
|
121
|
+
):
|
|
122
|
+
"""Builds a link button
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
url (str): button URL to open
|
|
126
|
+
label (str, optional): user-facing label
|
|
127
|
+
emoji (str | EmojiModel, optional): emoji icon as str or EmojiModel if custom
|
|
128
|
+
disabled (bool, optional): Whether the button should be disabled. Defaults to False.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
(Button): the button object
|
|
132
|
+
"""
|
|
133
|
+
btn = ComponentBuilder._basic_button(ButtonStyles.LINK, label, emoji, disabled)
|
|
134
|
+
btn.url = url
|
|
135
|
+
return btn
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def row(components: list[ActionRowChild]):
|
|
139
|
+
"""Shorthand for action row.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
components (list[ActionRowChild]): the action row objects.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
(ActionRowPart): the action row object
|
|
146
|
+
"""
|
|
147
|
+
if not isinstance(components, list):
|
|
148
|
+
components = [components]
|
|
149
|
+
|
|
150
|
+
return ActionRowPart(components)
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def option(
|
|
154
|
+
label: str,
|
|
155
|
+
value: str,
|
|
156
|
+
description: str = None,
|
|
157
|
+
emoji: EmojiModel | str = None,
|
|
158
|
+
default: bool = False
|
|
159
|
+
):
|
|
160
|
+
"""Builds a string menu select option.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
label (str): user-facing label
|
|
164
|
+
value (str): unique identifier
|
|
165
|
+
description (str, optional): option descriptor
|
|
166
|
+
emoji (EmojiModel | str, optional): emoji icon as str or EmojiModel if custom
|
|
167
|
+
default (bool, optional): Whether this value should be the default if none is selected. Defaults to False.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
(TypeError): invalid `emoji` type
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
(SelectOption): the SelectOption object
|
|
174
|
+
"""
|
|
175
|
+
if emoji:
|
|
176
|
+
if isinstance(emoji, str):
|
|
177
|
+
emoji = EmojiModel(name=emoji)
|
|
178
|
+
elif not isinstance(emoji, EmojiModel):
|
|
179
|
+
raise TypeError(f"EasyBot.primary expects type str or EmojiModel, got {type(emoji).__name__}")
|
|
180
|
+
|
|
181
|
+
return SelectOption(
|
|
182
|
+
label=label,
|
|
183
|
+
value=value,
|
|
184
|
+
description=description,
|
|
185
|
+
emoji=emoji,
|
|
186
|
+
default=default
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def short_text(
|
|
191
|
+
custom_id: str,
|
|
192
|
+
required: bool = True,
|
|
193
|
+
placeholder: str | None = None,
|
|
194
|
+
min_length: int | None = None,
|
|
195
|
+
max_length: int | None = None
|
|
196
|
+
):
|
|
197
|
+
"""Builds a TextInput with `TextInputStyles.SHORT` style.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
custom_id (str): unique identifier
|
|
201
|
+
required (bool, optional): Whether this field is required. Defaults to True.
|
|
202
|
+
placeholder (str | None, optional): default text if nothing is entered
|
|
203
|
+
min_length (int | None, optional): minimum input length
|
|
204
|
+
max_length (int | None, optional): maximum input length
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
(TextInput): the TextInput object
|
|
208
|
+
"""
|
|
209
|
+
return TextInput(
|
|
210
|
+
style=TextInputStyles.SHORT,
|
|
211
|
+
custom_id=custom_id,
|
|
212
|
+
required=required,
|
|
213
|
+
placeholder=placeholder,
|
|
214
|
+
min_length=min_length,
|
|
215
|
+
max_length=max_length
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def long_text(
|
|
220
|
+
custom_id: str,
|
|
221
|
+
required: bool = True,
|
|
222
|
+
placeholder: str | None = None,
|
|
223
|
+
min_length: int | None = None,
|
|
224
|
+
max_length: int | None = None
|
|
225
|
+
):
|
|
226
|
+
"""Builds a TextInput with `TextInputStyles.PARAGRAPH` style.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
custom_id (str): unique identifier
|
|
230
|
+
required (bool, optional): Whether this field is required. Defaults to True.
|
|
231
|
+
placeholder (str | None, optional): default text if nothing is entered
|
|
232
|
+
min_length (int | None, optional): minimum input length
|
|
233
|
+
max_length (int | None, optional): maximum input length
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
(TextInput): the TextInput object
|
|
237
|
+
"""
|
|
238
|
+
return TextInput(
|
|
239
|
+
style=TextInputStyles.PARAGRAPH,
|
|
240
|
+
custom_id=custom_id,
|
|
241
|
+
required=required,
|
|
242
|
+
placeholder=placeholder,
|
|
243
|
+
min_length=min_length,
|
|
244
|
+
max_length=max_length
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
@staticmethod
|
|
248
|
+
def role_value(id: int):
|
|
249
|
+
"""Builds a default role value.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
id (int): role ID
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
(DefaultValue): the DefaultValue object
|
|
256
|
+
"""
|
|
257
|
+
return DefaultValue(
|
|
258
|
+
id=id,
|
|
259
|
+
type='role'
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
@staticmethod
|
|
263
|
+
def user_value(id: int):
|
|
264
|
+
"""Builds a default user value.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
id (int): user ID
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
(DefaultValue): the DefaultValue object
|
|
271
|
+
"""
|
|
272
|
+
return DefaultValue(
|
|
273
|
+
id=id,
|
|
274
|
+
type='user'
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
@staticmethod
|
|
278
|
+
def channel_value(id: int):
|
|
279
|
+
"""Builds a default channel value.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
id (int): channel ID
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
(DefaultValue): the DefaultValue object
|
|
286
|
+
"""
|
|
287
|
+
return DefaultValue(
|
|
288
|
+
id=id,
|
|
289
|
+
type='channel'
|
|
290
|
+
)
|