omnivybe.py 1.0.0__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.
Files changed (33) hide show
  1. omnivybe_py-1.0.0/PKG-INFO +101 -0
  2. omnivybe_py-1.0.0/README.md +89 -0
  3. omnivybe_py-1.0.0/omnivybe/__init__.py +130 -0
  4. omnivybe_py-1.0.0/omnivybe/__main__.py +4 -0
  5. omnivybe_py-1.0.0/omnivybe/bitfields.py +126 -0
  6. omnivybe_py-1.0.0/omnivybe/builders.py +176 -0
  7. omnivybe_py-1.0.0/omnivybe/cdn.py +149 -0
  8. omnivybe_py-1.0.0/omnivybe/cli.py +65 -0
  9. omnivybe_py-1.0.0/omnivybe/client.py +119 -0
  10. omnivybe_py-1.0.0/omnivybe/collectors.py +133 -0
  11. omnivybe_py-1.0.0/omnivybe/constants.py +61 -0
  12. omnivybe_py-1.0.0/omnivybe/ext/__init__.py +1 -0
  13. omnivybe_py-1.0.0/omnivybe/ext/commands/__init__.py +5 -0
  14. omnivybe_py-1.0.0/omnivybe/ext/commands/bot.py +120 -0
  15. omnivybe_py-1.0.0/omnivybe/ext/commands/context.py +49 -0
  16. omnivybe_py-1.0.0/omnivybe/ext/commands/core.py +46 -0
  17. omnivybe_py-1.0.0/omnivybe/ext/paginator/__init__.py +3 -0
  18. omnivybe_py-1.0.0/omnivybe/ext/paginator/paginator.py +95 -0
  19. omnivybe_py-1.0.0/omnivybe/ext/tasks/__init__.py +3 -0
  20. omnivybe_py-1.0.0/omnivybe/ext/tasks/loop.py +74 -0
  21. omnivybe_py-1.0.0/omnivybe/gateway.py +179 -0
  22. omnivybe_py-1.0.0/omnivybe/ratelimit.py +30 -0
  23. omnivybe_py-1.0.0/omnivybe/rest.py +90 -0
  24. omnivybe_py-1.0.0/omnivybe/structures.py +260 -0
  25. omnivybe_py-1.0.0/omnivybe/utils.py +142 -0
  26. omnivybe_py-1.0.0/omnivybe.py.egg-info/PKG-INFO +101 -0
  27. omnivybe_py-1.0.0/omnivybe.py.egg-info/SOURCES.txt +31 -0
  28. omnivybe_py-1.0.0/omnivybe.py.egg-info/dependency_links.txt +1 -0
  29. omnivybe_py-1.0.0/omnivybe.py.egg-info/entry_points.txt +2 -0
  30. omnivybe_py-1.0.0/omnivybe.py.egg-info/requires.txt +1 -0
  31. omnivybe_py-1.0.0/omnivybe.py.egg-info/top_level.txt +1 -0
  32. omnivybe_py-1.0.0/pyproject.toml +28 -0
  33. omnivybe_py-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: omnivybe.py
3
+ Version: 1.0.0
4
+ Summary: The official, fully-featured, and high-performance Python bot SDK for the OmniVybe platform.
5
+ Author: OmniVybe Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://omnivybe.com.tr
8
+ Keywords: omnivybe,omni,omnivybe.py,bot,sdk,gateway,rest,chat
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: aiohttp>=3.9.0
12
+
13
+ # omnivybe.py
14
+
15
+ > The official, fully-featured, and high-performance Python bot SDK for the **OmniVybe** platform (1:1 feature parity with `omnivybe.js` + Next-Gen Python Extensions).
16
+
17
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
18
+ [![Python Version](https://img.shields.io/badge/python-3.9+-blue.svg?style=flat-square)](https://www.python.org/)
19
+
20
+ ---
21
+
22
+ ## 🚀 Kurulum
23
+
24
+ ```bash
25
+ pip install -e .
26
+ ```
27
+ veya doğrudan gereksinimleri yüklemek için:
28
+ ```bash
29
+ pip install -r requirements.txt
30
+ ```
31
+
32
+ ---
33
+
34
+ ## ⚡ Temel & Yaratıcı Özellikler
35
+
36
+ - 🎯 **Tam Bot ve Gateway Yaşam Döngüsü**: Otomatik heartbeat, yeniden bağlanma ve oturum yönetimi.
37
+ - 🛠️ **`omnivybe.ext.commands`**: Prefix tabanlı komut sistemi, akıllı `Context` (`ctx.reply`, `ctx.send`), alias ve dinamik prefix desteği.
38
+ - 🧩 **Sıcak Yeniden Yüklemeli Cog / Extension Desteği**: `bot.load_extension()` ve `bot.reload_extension()` ile botu kapatmadan canlı kod güncelleme.
39
+ - ⏱️ **`omnivybe.ext.tasks`**: `@tasks.loop(seconds=..., minutes=...)` ile kolay arka plan zamanlayıcıları.
40
+ - 📖 **`omnivybe.ext.paginator`**: Reaksiyon butonlu (◀️ ▶️ ⏹️) etkileşimli çok sayfalı Embed gezgini.
41
+ - 🚦 **`RateLimiter`**: Token-bucket tabanlı 429 koruması ve akıllı istek kuyruğu.
42
+ - 💎 **Gelişmiş Yapıcılar**: `EmbedBuilder`, `AttachmentBuilder`, `MessagePayload`.
43
+ - 🔍 **Kolektörler**: `MessageCollector`, `ReactionCollector`.
44
+ - 📂 **Model & Yapılar**: `User`, `GuildMember`, `Role`, `Message`, `TextChannel`, `VoiceChannel`, `CategoryChannel`, `ThreadChannel`, `Guild`.
45
+ - 🛡️ **Bitfield ve Yetki Denetimi**: `PermissionsBitField`, `MessageFlagsBitField`, `UserFlagsBitField`, `GatewayIntentBits`.
46
+ - 🌐 **CDN Yardımcıları**: `cdn_avatar_url`, `cdn_display_avatar_url`, `cdn_banner_url`, `cdn_emoji_url`, `cdn_sticker_url`, `cdn_guild_asset_url`.
47
+ - 🎨 **Emoji & Markdown Araçları**: `parse_emoji`, `format_emoji`, `get_unicode_from_shortcode`, `escape_markdown`, `format_timestamp`, `resolve_color`.
48
+ - 💻 **CLI Bot İskeleti**: `python -m omnivybe init` komutuyla tek tıkla hazır bot şablonu oluşturma.
49
+
50
+ ---
51
+
52
+ ## 📖 Hızlı Başlangıç
53
+
54
+ ### 1. `commands.Bot` ile Komut & Sayfalayıcı Örneği
55
+
56
+ ```python
57
+ import os
58
+ from omnivybe import GatewayIntentBits, EmbedBuilder
59
+ from omnivybe.ext import commands, tasks
60
+ from omnivybe.ext.paginator import Paginator
61
+
62
+ bot = commands.Bot(
63
+ command_prefix="!",
64
+ intents=GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages | GatewayIntentBits.MessageContent
65
+ )
66
+
67
+ @bot.event
68
+ async def on_ready():
69
+ print(f"🚀 Bot hazır: {bot.user.tag}")
70
+ durum_guncelleyici.start()
71
+
72
+ @bot.command(name="ping")
73
+ async def ping(ctx):
74
+ await ctx.reply("🏓 Pong! OmniVybe Framework çalışıyor.")
75
+
76
+ @bot.command(name="yardim")
77
+ async def yardim(ctx):
78
+ sayfa1 = EmbedBuilder().set_title("Yardım - Sayfa 1").set_description("Komut listesi başlangıcı...").set_color(0x5865F2)
79
+ sayfa2 = EmbedBuilder().set_title("Yardım - Sayfa 2").set_description("Moderasyon komutları...").set_color(0x57F287)
80
+
81
+ paginator = Paginator([sayfa1, sayfa2], timeout=30.0)
82
+ await paginator.start(ctx)
83
+
84
+ @tasks.loop(seconds=60)
85
+ async def durum_guncelleyici():
86
+ print("Durum kontrol ediliyor...")
87
+
88
+ bot.run(os.environ.get("OMNIVYBE_BOT_TOKEN", "YOUR_BOT_TOKEN"))
89
+ ```
90
+
91
+ ### 2. CLI ile Proje Başlatma
92
+
93
+ ```bash
94
+ python -m omnivybe init my_bot
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 📄 Lisans
100
+
101
+ Bu proje MIT lisansı altındadır.
@@ -0,0 +1,89 @@
1
+ # omnivybe.py
2
+
3
+ > The official, fully-featured, and high-performance Python bot SDK for the **OmniVybe** platform (1:1 feature parity with `omnivybe.js` + Next-Gen Python Extensions).
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
6
+ [![Python Version](https://img.shields.io/badge/python-3.9+-blue.svg?style=flat-square)](https://www.python.org/)
7
+
8
+ ---
9
+
10
+ ## 🚀 Kurulum
11
+
12
+ ```bash
13
+ pip install -e .
14
+ ```
15
+ veya doğrudan gereksinimleri yüklemek için:
16
+ ```bash
17
+ pip install -r requirements.txt
18
+ ```
19
+
20
+ ---
21
+
22
+ ## ⚡ Temel & Yaratıcı Özellikler
23
+
24
+ - 🎯 **Tam Bot ve Gateway Yaşam Döngüsü**: Otomatik heartbeat, yeniden bağlanma ve oturum yönetimi.
25
+ - 🛠️ **`omnivybe.ext.commands`**: Prefix tabanlı komut sistemi, akıllı `Context` (`ctx.reply`, `ctx.send`), alias ve dinamik prefix desteği.
26
+ - 🧩 **Sıcak Yeniden Yüklemeli Cog / Extension Desteği**: `bot.load_extension()` ve `bot.reload_extension()` ile botu kapatmadan canlı kod güncelleme.
27
+ - ⏱️ **`omnivybe.ext.tasks`**: `@tasks.loop(seconds=..., minutes=...)` ile kolay arka plan zamanlayıcıları.
28
+ - 📖 **`omnivybe.ext.paginator`**: Reaksiyon butonlu (◀️ ▶️ ⏹️) etkileşimli çok sayfalı Embed gezgini.
29
+ - 🚦 **`RateLimiter`**: Token-bucket tabanlı 429 koruması ve akıllı istek kuyruğu.
30
+ - 💎 **Gelişmiş Yapıcılar**: `EmbedBuilder`, `AttachmentBuilder`, `MessagePayload`.
31
+ - 🔍 **Kolektörler**: `MessageCollector`, `ReactionCollector`.
32
+ - 📂 **Model & Yapılar**: `User`, `GuildMember`, `Role`, `Message`, `TextChannel`, `VoiceChannel`, `CategoryChannel`, `ThreadChannel`, `Guild`.
33
+ - 🛡️ **Bitfield ve Yetki Denetimi**: `PermissionsBitField`, `MessageFlagsBitField`, `UserFlagsBitField`, `GatewayIntentBits`.
34
+ - 🌐 **CDN Yardımcıları**: `cdn_avatar_url`, `cdn_display_avatar_url`, `cdn_banner_url`, `cdn_emoji_url`, `cdn_sticker_url`, `cdn_guild_asset_url`.
35
+ - 🎨 **Emoji & Markdown Araçları**: `parse_emoji`, `format_emoji`, `get_unicode_from_shortcode`, `escape_markdown`, `format_timestamp`, `resolve_color`.
36
+ - 💻 **CLI Bot İskeleti**: `python -m omnivybe init` komutuyla tek tıkla hazır bot şablonu oluşturma.
37
+
38
+ ---
39
+
40
+ ## 📖 Hızlı Başlangıç
41
+
42
+ ### 1. `commands.Bot` ile Komut & Sayfalayıcı Örneği
43
+
44
+ ```python
45
+ import os
46
+ from omnivybe import GatewayIntentBits, EmbedBuilder
47
+ from omnivybe.ext import commands, tasks
48
+ from omnivybe.ext.paginator import Paginator
49
+
50
+ bot = commands.Bot(
51
+ command_prefix="!",
52
+ intents=GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages | GatewayIntentBits.MessageContent
53
+ )
54
+
55
+ @bot.event
56
+ async def on_ready():
57
+ print(f"🚀 Bot hazır: {bot.user.tag}")
58
+ durum_guncelleyici.start()
59
+
60
+ @bot.command(name="ping")
61
+ async def ping(ctx):
62
+ await ctx.reply("🏓 Pong! OmniVybe Framework çalışıyor.")
63
+
64
+ @bot.command(name="yardim")
65
+ async def yardim(ctx):
66
+ sayfa1 = EmbedBuilder().set_title("Yardım - Sayfa 1").set_description("Komut listesi başlangıcı...").set_color(0x5865F2)
67
+ sayfa2 = EmbedBuilder().set_title("Yardım - Sayfa 2").set_description("Moderasyon komutları...").set_color(0x57F287)
68
+
69
+ paginator = Paginator([sayfa1, sayfa2], timeout=30.0)
70
+ await paginator.start(ctx)
71
+
72
+ @tasks.loop(seconds=60)
73
+ async def durum_guncelleyici():
74
+ print("Durum kontrol ediliyor...")
75
+
76
+ bot.run(os.environ.get("OMNIVYBE_BOT_TOKEN", "YOUR_BOT_TOKEN"))
77
+ ```
78
+
79
+ ### 2. CLI ile Proje Başlatma
80
+
81
+ ```bash
82
+ python -m omnivybe init my_bot
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 📄 Lisans
88
+
89
+ Bu proje MIT lisansı altındadır.
@@ -0,0 +1,130 @@
1
+ """
2
+ omnivybe.py
3
+ ~~~~~~~~~~~
4
+ The official, high-performance Python bot SDK for the OmniVybe platform.
5
+ Full feature parity with omni.js / omnivybe.js plus next-gen extensions.
6
+ """
7
+
8
+ from .bitfields import (
9
+ BitField,
10
+ MessageFlags,
11
+ MessageFlagsBitField,
12
+ PermissionFlags,
13
+ PermissionsBitField,
14
+ PublicUserFlags,
15
+ UserFlagsBitField,
16
+ )
17
+ from .builders import AttachmentBuilder, EmbedBuilder, MessagePayload
18
+ from .cdn import (
19
+ CDN_URL,
20
+ STATIC_CDN_URL,
21
+ cdn_avatar_url,
22
+ cdn_banner_url,
23
+ cdn_default_avatar_url,
24
+ cdn_display_avatar_url,
25
+ cdn_emoji_url,
26
+ cdn_guild_asset_url,
27
+ cdn_member_avatar_url,
28
+ cdn_member_banner_url,
29
+ cdn_sticker_url,
30
+ )
31
+ from .client import Client
32
+ from .collectors import BaseCollector, MessageCollector, ReactionCollector
33
+ from .constants import ChannelType, Constants, GatewayIntentBits, GatewayOpcodes
34
+ from .gateway import GatewayManager
35
+ from .ratelimit import RateLimiter
36
+ from .rest import RESTManager
37
+ from .structures import (
38
+ Base,
39
+ CategoryChannel,
40
+ Embed,
41
+ Guild,
42
+ GuildMember,
43
+ Message,
44
+ Role,
45
+ TextChannel,
46
+ ThreadChannel,
47
+ User,
48
+ VoiceChannel,
49
+ )
50
+ from .utils import (
51
+ ParsedEmoji,
52
+ escape_markdown,
53
+ format_color,
54
+ format_emoji,
55
+ format_timestamp,
56
+ get_unicode_from_shortcode,
57
+ parse_emoji,
58
+ parse_role_mention,
59
+ parse_user_mention,
60
+ resolve_color,
61
+ )
62
+
63
+ # Extension namespaces
64
+ from . import ext
65
+
66
+ __version__ = "1.1.0"
67
+ __all__ = [
68
+ # Core
69
+ "Client",
70
+ "GatewayManager",
71
+ "RESTManager",
72
+ "RateLimiter",
73
+ "Constants",
74
+ "GatewayOpcodes",
75
+ "GatewayIntentBits",
76
+ "ChannelType",
77
+ # Structures
78
+ "Base",
79
+ "User",
80
+ "GuildMember",
81
+ "Role",
82
+ "Message",
83
+ "TextChannel",
84
+ "VoiceChannel",
85
+ "CategoryChannel",
86
+ "ThreadChannel",
87
+ "Guild",
88
+ "Embed",
89
+ # Builders & Payloads
90
+ "EmbedBuilder",
91
+ "AttachmentBuilder",
92
+ "MessagePayload",
93
+ # Collectors
94
+ "BaseCollector",
95
+ "MessageCollector",
96
+ "ReactionCollector",
97
+ # BitFields
98
+ "BitField",
99
+ "PermissionFlags",
100
+ "PermissionsBitField",
101
+ "MessageFlags",
102
+ "MessageFlagsBitField",
103
+ "PublicUserFlags",
104
+ "UserFlagsBitField",
105
+ # CDN
106
+ "CDN_URL",
107
+ "STATIC_CDN_URL",
108
+ "cdn_avatar_url",
109
+ "cdn_display_avatar_url",
110
+ "cdn_banner_url",
111
+ "cdn_member_avatar_url",
112
+ "cdn_member_banner_url",
113
+ "cdn_default_avatar_url",
114
+ "cdn_guild_asset_url",
115
+ "cdn_emoji_url",
116
+ "cdn_sticker_url",
117
+ # Utils
118
+ "ParsedEmoji",
119
+ "parse_emoji",
120
+ "format_emoji",
121
+ "get_unicode_from_shortcode",
122
+ "escape_markdown",
123
+ "resolve_color",
124
+ "format_color",
125
+ "format_timestamp",
126
+ "parse_role_mention",
127
+ "parse_user_mention",
128
+ # Extensions
129
+ "ext",
130
+ ]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,126 @@
1
+ from enum import IntFlag
2
+ from typing import Any, List, Set, Union
3
+
4
+
5
+ class BitField:
6
+ FLAGS: type = IntFlag
7
+
8
+ def __init__(self, bitfield: Union[int, List[Union[int, IntFlag]], IntFlag] = 0):
9
+ if isinstance(bitfield, list):
10
+ self.value = 0
11
+ for b in bitfield:
12
+ self.value |= int(b)
13
+ else:
14
+ self.value = int(bitfield)
15
+
16
+ def has(self, flag: Union[int, IntFlag]) -> bool:
17
+ val = int(flag)
18
+ return (self.value & val) == val
19
+
20
+ def add(self, *flags: Union[int, IntFlag]) -> None:
21
+ for f in flags:
22
+ self.value |= int(f)
23
+
24
+ def remove(self, *flags: Union[int, IntFlag]) -> None:
25
+ for f in flags:
26
+ self.value &= ~int(f)
27
+
28
+ def to_list(self) -> List[str]:
29
+ names: List[str] = []
30
+ for name, member in self.FLAGS.__members__.items():
31
+ if self.has(member.value):
32
+ names.append(name)
33
+ return names
34
+
35
+ def __int__(self) -> int:
36
+ return self.value
37
+
38
+ def __repr__(self) -> str:
39
+ return f"<{self.__class__.__name__} value={self.value}>"
40
+
41
+
42
+ class PermissionFlags(IntFlag):
43
+ CreateInstantInvite = 1 << 0
44
+ KickMembers = 1 << 1
45
+ BanMembers = 1 << 2
46
+ Administrator = 1 << 3
47
+ ManageChannels = 1 << 4
48
+ ManageGuild = 1 << 5
49
+ AddReactions = 1 << 6
50
+ ViewAuditLog = 1 << 7
51
+ PrioritySpeaker = 1 << 8
52
+ Stream = 1 << 9
53
+ ViewChannel = 1 << 10
54
+ SendMessages = 1 << 11
55
+ SendTTSMessages = 1 << 12
56
+ ManageMessages = 1 << 13
57
+ EmbedLinks = 1 << 14
58
+ AttachFiles = 1 << 15
59
+ ReadMessageHistory = 1 << 16
60
+ MentionEveryone = 1 << 17
61
+ UseExternalEmojis = 1 << 18
62
+ ViewGuildInsights = 1 << 19
63
+ Connect = 1 << 20
64
+ Speak = 1 << 21
65
+ MuteMembers = 1 << 22
66
+ DeafenMembers = 1 << 23
67
+ MoveMembers = 1 << 24
68
+ UseVAD = 1 << 25
69
+ ChangeNickname = 1 << 26
70
+ ManageNicknames = 1 << 27
71
+ ManageRoles = 1 << 28
72
+ ManageWebhooks = 1 << 29
73
+ ManageEmojisAndStickers = 1 << 30
74
+ UseApplicationCommands = 1 << 31
75
+ RequestToSpeak = 1 << 32
76
+ ManageEvents = 1 << 33
77
+ ManageThreads = 1 << 34
78
+ CreatePublicThreads = 1 << 35
79
+ CreatePrivateThreads = 1 << 36
80
+ UseExternalStickers = 1 << 37
81
+ SendMessagesInThreads = 1 << 38
82
+ ModerateMembers = 1 << 40
83
+
84
+
85
+ class PermissionsBitField(BitField):
86
+ FLAGS = PermissionFlags
87
+
88
+
89
+ class MessageFlags(IntFlag):
90
+ Crossposted = 1 << 0
91
+ IsCrosspost = 1 << 1
92
+ SuppressEmbeds = 1 << 2
93
+ SourceMessageDeleted = 1 << 3
94
+ Urgent = 1 << 4
95
+ HasThread = 1 << 5
96
+ Ephemeral = 1 << 6
97
+ Loading = 1 << 7
98
+ FailedToMentionSomeRolesInThread = 1 << 8
99
+ SuppressNotifications = 1 << 12
100
+ IsVoiceMessage = 1 << 13
101
+
102
+
103
+ class MessageFlagsBitField(BitField):
104
+ FLAGS = MessageFlags
105
+
106
+
107
+ class PublicUserFlags(IntFlag):
108
+ Staff = 1 << 0
109
+ Partner = 1 << 1
110
+ Hypesquad = 1 << 2
111
+ BugHunterLevel1 = 1 << 3
112
+ HypeSquadOnlineHouse1 = 1 << 6
113
+ HypeSquadOnlineHouse2 = 1 << 7
114
+ HypeSquadOnlineHouse3 = 1 << 8
115
+ PremiumEarlySupporter = 1 << 9
116
+ TeamPseudoUser = 1 << 10
117
+ BugHunterLevel2 = 1 << 14
118
+ VerifiedBot = 1 << 16
119
+ VerifiedDeveloper = 1 << 17
120
+ CertifiedModerator = 1 << 18
121
+ BotHTTPInteractions = 1 << 19
122
+ ActiveDeveloper = 1 << 22
123
+
124
+
125
+ class UserFlagsBitField(BitField):
126
+ FLAGS = PublicUserFlags
@@ -0,0 +1,176 @@
1
+ from datetime import datetime
2
+ import io
3
+ import os
4
+ from typing import Any, Dict, List, Optional, Union
5
+ from .utils import resolve_color
6
+
7
+
8
+ class AttachmentBuilder:
9
+ def __init__(
10
+ self,
11
+ data: Optional[Union[bytes, io.BytesIO, str]] = None,
12
+ *,
13
+ name: Optional[str] = None,
14
+ description: Optional[str] = None
15
+ ):
16
+ self.name: str = name or "file"
17
+ self.description: Optional[str] = description
18
+ self._data: Optional[Union[bytes, io.BytesIO, str]] = data
19
+
20
+ def set_name(self, name: str) -> "AttachmentBuilder":
21
+ self.name = name
22
+ return self
23
+
24
+ def set_description(self, description: str) -> "AttachmentBuilder":
25
+ self.description = description
26
+ return self
27
+
28
+ def set_file(self, data: Union[bytes, io.BytesIO, str]) -> "AttachmentBuilder":
29
+ self._data = data
30
+ return self
31
+
32
+ def get_bytes(self) -> bytes:
33
+ if self._data is None:
34
+ return b""
35
+ if isinstance(self._data, bytes):
36
+ return self._data
37
+ if isinstance(self._data, io.BytesIO):
38
+ return self._data.getvalue()
39
+ if isinstance(self._data, str):
40
+ if os.path.exists(self._data):
41
+ with open(self._data, "rb") as f:
42
+ return f.read()
43
+ return self._data.encode("utf-8")
44
+ return b""
45
+
46
+ def to_dict(self, id_val: int = 0) -> Dict[str, Any]:
47
+ d: Dict[str, Any] = {
48
+ "id": id_val,
49
+ "filename": self.name
50
+ }
51
+ if self.description:
52
+ d["description"] = self.description
53
+ return d
54
+
55
+
56
+ class EmbedBuilder:
57
+ def __init__(self):
58
+ self.title: Optional[str] = None
59
+ self.description: Optional[str] = None
60
+ self.url: Optional[str] = None
61
+ self.color: Optional[int] = None
62
+ self.timestamp: Optional[str] = None
63
+ self.footer: Optional[Dict[str, str]] = None
64
+ self.image: Optional[Dict[str, str]] = None
65
+ self.thumbnail: Optional[Dict[str, str]] = None
66
+ self.author: Optional[Dict[str, str]] = None
67
+ self.fields: List[Dict[str, Any]] = []
68
+
69
+ def set_title(self, title: str) -> "EmbedBuilder":
70
+ self.title = title
71
+ return self
72
+
73
+ def set_description(self, description: str) -> "EmbedBuilder":
74
+ self.description = description
75
+ return self
76
+
77
+ def set_url(self, url: str) -> "EmbedBuilder":
78
+ self.url = url
79
+ return self
80
+
81
+ def set_color(self, color: Union[int, str, List[int], tuple]) -> "EmbedBuilder":
82
+ self.color = resolve_color(color)
83
+ return self
84
+
85
+ def set_timestamp(self, timestamp: Optional[Union[datetime, str]] = None) -> "EmbedBuilder":
86
+ if timestamp is None:
87
+ self.timestamp = datetime.utcnow().isoformat() + "Z"
88
+ elif isinstance(timestamp, datetime):
89
+ self.timestamp = timestamp.isoformat() + "Z"
90
+ else:
91
+ self.timestamp = str(timestamp)
92
+ return self
93
+
94
+ def set_footer(self, *, text: str, icon_url: Optional[str] = None) -> "EmbedBuilder":
95
+ f = {"text": text}
96
+ if icon_url:
97
+ f["icon_url"] = icon_url
98
+ self.footer = f
99
+ return self
100
+
101
+ def set_image(self, url: str) -> "EmbedBuilder":
102
+ self.image = {"url": url}
103
+ return self
104
+
105
+ def set_thumbnail(self, url: str) -> "EmbedBuilder":
106
+ self.thumbnail = {"url": url}
107
+ return self
108
+
109
+ def set_author(self, *, name: str, icon_url: Optional[str] = None, url: Optional[str] = None) -> "EmbedBuilder":
110
+ a = {"name": name}
111
+ if icon_url:
112
+ a["icon_url"] = icon_url
113
+ if url:
114
+ a["url"] = url
115
+ self.author = a
116
+ return self
117
+
118
+ def add_field(self, *, name: str, value: str, inline: bool = False) -> "EmbedBuilder":
119
+ self.fields.append({"name": name, "value": value, "inline": inline})
120
+ return self
121
+
122
+ def to_dict(self) -> Dict[str, Any]:
123
+ data: Dict[str, Any] = {}
124
+ if self.title:
125
+ data["title"] = self.title
126
+ if self.description:
127
+ data["description"] = self.description
128
+ if self.url:
129
+ data["url"] = self.url
130
+ if self.color is not None:
131
+ data["color"] = self.color
132
+ if self.timestamp:
133
+ data["timestamp"] = self.timestamp
134
+ if self.footer:
135
+ data["footer"] = self.footer
136
+ if self.image:
137
+ data["image"] = self.image
138
+ if self.thumbnail:
139
+ data["thumbnail"] = self.thumbnail
140
+ if self.author:
141
+ data["author"] = self.author
142
+ if self.fields:
143
+ data["fields"] = self.fields
144
+ return data
145
+
146
+
147
+ class MessagePayload:
148
+ @staticmethod
149
+ def create(
150
+ content: Optional[str] = None,
151
+ *,
152
+ embeds: Optional[List[Union[EmbedBuilder, Dict[str, Any]]]] = None,
153
+ files: Optional[List[AttachmentBuilder]] = None,
154
+ flags: Optional[int] = None,
155
+ reply_to_id: Optional[str] = None,
156
+ channel_id: Optional[str] = None,
157
+ guild_id: Optional[str] = None
158
+ ) -> Dict[str, Any]:
159
+ payload: Dict[str, Any] = {}
160
+ if content is not None:
161
+ payload["content"] = str(content)
162
+
163
+ if embeds:
164
+ payload["embeds"] = [e.to_dict() if hasattr(e, "to_dict") else e for e in embeds]
165
+
166
+ if flags is not None:
167
+ payload["flags"] = int(flags)
168
+
169
+ if reply_to_id and channel_id:
170
+ payload["message_reference"] = {
171
+ "message_id": str(reply_to_id),
172
+ "channel_id": str(channel_id),
173
+ "guild_id": str(guild_id) if guild_id else None
174
+ }
175
+
176
+ return payload