diff options
Diffstat (limited to 'discord')
-rw-r--r-- | discord/client.py | 14 | ||||
-rw-r--r-- | discord/flags.py | 35 | ||||
-rw-r--r-- | discord/intents.py | 56 | ||||
-rw-r--r-- | discord/premium_type.py | 8 | ||||
-rw-r--r-- | discord/user.py | 130 | ||||
-rw-r--r-- | discord/utils/exceptions.py | 3 | ||||
-rw-r--r-- | discord/utils/rest.py | 60 |
7 files changed, 262 insertions, 44 deletions
diff --git a/discord/client.py b/discord/client.py index d272130..c725e3c 100644 --- a/discord/client.py +++ b/discord/client.py @@ -8,7 +8,8 @@ import zlib import websockets from .utils import EventEmitter -from .intents import Intents, gen_number +from .utils.rest import get +from .intents import Intents, get_number from .user import User class GatewayEvents(IntEnum): @@ -26,10 +27,17 @@ class GatewayEvents(IntEnum): HEARTBEAT_ACK = 11 GUILD_SYNC = 12 class Client: + _token: str + + @property + async def user(self): + data = await get(self._token, '/users/@me') + return User(data) + def __init__(self, intents: list[Intents]): self.gateway = None self.loop = asyncio.get_event_loop() - self.code: int = gen_number(intents) + self.code: int = get_number(intents) self.event_emitter = EventEmitter() self.buffer = bytearray() self.inflator = zlib.decompressobj() @@ -37,7 +45,7 @@ class Client: self.token: str = None self.ready: bool = False - async def connect(self, token: str, intent_code: int): + async def connect(self): async with websockets.connect("wss://gateway.discord.gg/?v=10&encoding=json") as gateway: self.gateway = gateway threading.Thread(target=self.loop.run_forever).start() diff --git a/discord/flags.py b/discord/flags.py new file mode 100644 index 0000000..65a9253 --- /dev/null +++ b/discord/flags.py @@ -0,0 +1,35 @@ +from enum import Enum, unique + + +@unique +class Flags(Enum): + STAFF = 1 + PARTNER = 2 + HYPESQUAD = 4 + BUG_HUNTER_LEVEL_1 = 8 + HYPESQUAD_ONLINE_HOUSE_1 = 64 + HYPESQUAD_ONLINE_HOUSE_2 = 128 + HYPESQUAD_ONLINE_HOUSE_3 = 256 + TEAM_PSUEDO_USER = 1024 + BUG_HUNTER_LEVEL_2 = 16384 + VERIFIED_BOT = 65536 + VERIFIED_DEVELOPER = 131072 + CERTIFIED_MODERATOR = 262144 + BOT_HTTP_INTERACTIONS = 524288 + + +def get_number(flags: list[Flags]): + number = 1 + for i in flags: + number += i.value + return number + +def get_flags(number: int): + flags = [] + while number != 0: + for i in Flags: + if number >= i.value: + flags.append(i) + number -= i.value + return flags + diff --git a/discord/intents.py b/discord/intents.py index 2e993ea..f538fb6 100644 --- a/discord/intents.py +++ b/discord/intents.py @@ -15,28 +15,28 @@ class Intents(Enum): See more at: https://discord.com/developers/docs/topics/gateway#gateway-intents """ - GUILDS = 0 - GUILD_MEMBERS = 1 - GUILD_BANS = 2 - GUILD_EMOJIS_AND_STICKERS = 3 - GUILD_INTEGRATIONS = 4 - GUILD_WEBHOOKS = 5 - GUILD_INVITES = 6 - GUILD_VOICE_STATES = 7 - GUILD_PRESENCES = 8 - GUILD_MESSAGES = 9 - GUILD_MESSAGE_REACTIONS = 10 - GUILD_MESSAGE_TYPING = 11 - DIRECT_MESSAGES = 12 - DIRECT_MESSAGE_REACTIONS = 13 - DIRECT_MESSAGE_TYPING = 14 - MESSAGE_CONTENT = 15 - GUILD_SCHEDULED_EVENTS = 16 - AUTO_MODERATION_CONFIGURATION = 20 - AUTO_MODERATION_EXECUTION = 21 - - -def gen_number(intents: list[Intents]): + GUILDS = 1 + GUILD_MEMBERS = 2 + GUILD_BANS = 4 + GUILD_EMOJIS_AND_STICKERS = 8 + GUILD_INTEGRATIONS = 16 + GUILD_WEBHOOKS = 32 + GUILD_INVITES = 64 + GUILD_VOICE_STATES = 128 + GUILD_PRESENCES = 256 + GUILD_MESSAGES = 512 + GUILD_MESSAGE_REACTIONS = 1024 + GUILD_MESSAGE_TYPING = 2048 + DIRECT_MESSAGES = 4096 + DIRECT_MESSAGE_REACTIONS = 8192 + DIRECT_MESSAGE_TYPING = 16384 + MESSAGE_CONTENT = 32768 + GUILD_SCHEDULED_EVENTS = 65536 + AUTO_MODERATION_CONFIGURATION = 1048576 + AUTO_MODERATION_EXECUTION = 2097152 + + +def get_number(intents: list[Intents]): """ Generates the number used to tell the gateway which intents are active. @@ -48,5 +48,15 @@ def gen_number(intents: list[Intents]): """ number = 1 for i in intents: - number << i.value + number += i.value return number + + +def get_intents(number: int): + intents = [] + while number != 0: + for i in Intents: + if number >= i.value: + intents.append(i) + number -= i.value + return intents diff --git a/discord/premium_type.py b/discord/premium_type.py new file mode 100644 index 0000000..3549f92 --- /dev/null +++ b/discord/premium_type.py @@ -0,0 +1,8 @@ +from enum import Enum, unique + + +@unique +class PremiumType(Enum): + NONE = 0, + NITRO_CLASSIC = 1, + NITRO = 2 \ No newline at end of file diff --git a/discord/user.py b/discord/user.py index 16ddf1b..ff86c26 100644 --- a/discord/user.py +++ b/discord/user.py @@ -1,22 +1,116 @@ +from discord.flags import get_flags, Flags +from discord.premium_type import PremiumType + + class User: - __slots__ = ( - "id", - "username", - "discriminator", - "avatar", - "bot", - "system", - "mfa_enabled", - "banner", - "accent_color", - "locale", - "verified", - "email", - "flags", - "premium_type", - "public_flags" - ) + _id: int + _username: str + _discriminator: str + _avatar: str + _bot: bool + _system: bool + _mfa_enabled: bool + _banner: str + _accent_color: int + _locale: str + _verified: bool + _email: str + _pronouns: str + _bio: str + _flags: list[Flags] + _premium_type: PremiumType + _public_flags: list[Flags] + + @property + def id(self): + """The user's ID.""" + return self._id + + @property + def username(self): + """The user's username. This is not unique.""" + return self._username + + @property + def discriminator(self): + """The user's 4-digit tag.""" + return self._discriminator + + @property + def avatar(self): + """The user's avatar hash.""" + return self._avatar + + @property + def bot(self): + """Whether the user is a bot.""" + return self._bot + + @property + def pronouns(self): + """The user's pronouns (not yet implemented into Discord frontend).""" + return self._pronouns + + @property + def bio(self): + """The contents of the user's About Me section.""" + return self._bio + + @property + def system(self): + """Whether the user is an Official Discord System user (for urgent messages).""" + return self._system + + @property + def mfa_enabled(self): + """Whether the user has 2FA set up.""" + return self._mfa_enabled + + @property + def banner(self): + """The user's banner hash.""" + return self._banner + + @property + def accent_color(self): + """The user's banner color.""" + return self._accent_color + + @property + def locale(self): + """The user's chosen language.""" + return self._locale + + @property + def verified(self): + """Whether the email on the user's account is verified.""" + return self._verified + + @property + def email(self): + """The user's email.""" + return self._email + + @property + def flags(self): + """The flags on the user's account.""" + return self._flags + + @property + def premium_type(self): + """The type of Nitro subscription on a user's account.""" + return self._premium_type + + @property + def public_flags(self): + """The public flags on a user's account.""" + return self._public_flags def __init__(self, data: dict): for k in data: - setattr(self, k, data[k]) + if k == "flags" or k == "public_flags": + setattr(self, f"_{k}", get_flags(data[k])) + elif k == "premium_type": + setattr(self, f"_{k}", PremiumType(data[k])) + else: + setattr(self, f"_{k}", data[k]) diff --git a/discord/utils/exceptions.py b/discord/utils/exceptions.py new file mode 100644 index 0000000..a7f035c --- /dev/null +++ b/discord/utils/exceptions.py @@ -0,0 +1,3 @@ +class APIException(Exception): + """Raised when the Discord API returns an error.""" + diff --git a/discord/utils/rest.py b/discord/utils/rest.py new file mode 100644 index 0000000..f7f6ab8 --- /dev/null +++ b/discord/utils/rest.py @@ -0,0 +1,60 @@ +import aiohttp +import asyncio + +from discord.utils.exceptions import APIException + + +async def get(token, url): + async with aiohttp.ClientSession(headers={ + "Authorization": f"Bot {token}", + "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)" + }) as session: + async with session.get(url='https://discord.com/api/v10' + url) as r: + data = await r.json() + match r.status: + case 200: + return data + case other: + raise APIException(data['message']) + + +async def post(token, url, data): + async with aiohttp.ClientSession(headers={ + "Authorization": f"Bot {token}", + "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)" + }) as session: + async with session.post(url='https://discord.com/api/v10' + url, data=data) as r: + data = await r.json() + match r.status: + case 200 | 204: + return data + case other: + raise APIException(data['message']) + + +async def patch(token, url, data): + async with aiohttp.ClientSession(headers={ + "Authorization": f"Bot {token}", + "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)" + }) as session: + async with session.patch(url='https://discord.com/api/v10' + url, data=data) as r: + data = await r.json() + match r.status: + case 200 | 204: + return data + case other: + raise APIException(data['message']) + + +async def delete(token, url): + async with aiohttp.ClientSession(headers={ + "Authorization": f"Bot {token}", + "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)" + }) as session: + async with session.delete(url='https://discord.com/api/v10' + url) as r: + data = await r.json() + match r.status: + case 200: + return data + case other: + raise APIException(data['message']) |