Skip to content

Instantly share code, notes, and snippets.

@1oonie
Created August 28, 2021 17:36
Show Gist options
  • Save 1oonie/dbe8b9b6c09c876d19786ba00cd4e5c1 to your computer and use it in GitHub Desktop.
Save 1oonie/dbe8b9b6c09c876d19786ba00cd4e5c1 to your computer and use it in GitHub Desktop.
import discord
import inspect
def _get_options(callback):
sig = inspect.signature(callback)
options = []
types = {
str: 3,
int: 4,
bool: 5,
discord.User: 6,
discord.abc.GuildChannel: 7,
discord.Role: 8,
float: 10
}
iterator = iter(sig.parameters.items())
next(iterator)
for name, param in iterator:
if not isinstance(param.annotation, Option):
raise TypeError(f'annotation must be `Option` not {param.annotation!r}')
option = {}
option['type'] = types[param.annotation.type]
option['name'] = name
# I couldn't think of a way to do this properly...
option['description'] = param.annotation.description
option['required'] = param.default == inspect._empty
options.append(option)
return options if options else None
class Command:
def __init__(self, callback, options):
self.callback = callback
self.options = options
class Option:
def __init__(self, type, description):
self.type = type
self.description = description
class Client(discord.Client):
def __init__(self, *args, **kwargs):
self.commands = {}
super().__init__(*args, **kwargs)
def _resolve_options(self, interaction, data):
args = []
for num, option in enumerate(data['options']):
if option['type'] in (3, 4, 5, 10):
args.append(option['value'])
continue
elif option['type'] == 6:
user_data = data['resolved']['users'][option['value']]
try:
member_data = data['resolved']['members'][option['value']]
except KeyError:
user = discord.User(state=self._get_state(), data=user_data)
else:
member_data['user'] = user_data
user = discord.Member(data=member_data, guild=interaction.guild, state=self._get_state())
finally:
args.append(user)
elif option['type'] == 7:
args.append(interaction.guild.get_channel(int(option['value'])))
elif option['type'] == 8:
args.append(interaction.guild.get_role(int(option['value'])))
return args
async def on_interaction(self, interaction):
data = interaction.data
if data['type'] == 1:
command = self.commands[data['id']]
if 'options' in data:
args = self._resolve_options(interaction, data)
await command.callback(interaction, *args)
else:
await command.callback(interaction)
def command(self, *, name, description, guild_id=None):
def inner(func):
options = _get_options(func)
command = Command(func, options)
async def task():
await self.wait_until_ready()
payload = {
'name': name,
'description': description
}
if command.options is not None:
payload['options'] = command.options
if guild_id is not None:
resp = await self.http.upsert_guild_command(self.user.id, guild_id, payload)
else:
resp = await self.http.upsert_global_command(self.user.id, payload)
command.id = resp['id']
self.commands[resp['id']] = command
self.loop.create_task(task())
return command
return inner
client = Client()
@client.command(name='userinfo', description='Display information on a user.', guild_id=862374318913355776)
async def test(interaction, user: Option(discord.User, 'The user you want to display information on.')=None):
user = user or interaction.user
e = discord.Embed()
roles = [role.name.replace('@', '@\u200b') for role in getattr(user, 'roles', [])]
e.set_author(name=str(user))
def format_date(dt):
if dt is None:
return 'N/A'
return f'{discord.utils.format_dt(dt, "F")} ({discord.utils.format_dt(dt, "R")})'
e.add_field(name='ID', value=user.id, inline=False)
e.add_field(name='Joined', value=format_date(getattr(user, 'joined_at', None)), inline=False)
e.add_field(name='Created', value=format_date(user.created_at), inline=False)
voice = getattr(user, 'voice', None)
if voice is not None:
vc = voice.channel
other_people = len(vc.members) - 1
voice = f'{vc.name} with {other_people} others' if other_people else f'{vc.name} by themselves'
e.add_field(name='Voice', value=voice, inline=False)
if roles:
e.add_field(name='Roles', value=', '.join(roles) if len(roles) < 10 else f'{len(roles)} roles', inline=False)
colour = user.colour
if colour.value:
e.colour = colour
e.set_thumbnail(url=user.display_avatar.url)
await interaction.response.send_message(embed=e, ephemeral=True)
client.run(token)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment