Skip to content

Instantly share code, notes, and snippets.

@Rapptz
Last active Oct 3, 2021
Embed
What would you like to do?
Showing off custom commands using discord.ext
import discord
from discord.ext import commands
import json, inspect
import functools
import re
# some JSON set up for our storage because >lazy<
class CustomCommandEntry:
__slots__ = ['name', 'content', 'guild_id']
def __init__(self, **kwargs):
self.name = kwargs.pop('name', None)
self.content = kwargs.pop('content', None)
self.guild_id = kwargs.pop('guild_id', None)
def __repr__(self):
return '<CustomCommandEntry name={0.name} content={0.content} guild_id={0.guild_id}>'.format(self)
class CustomCommandEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, CustomCommandEntry):
payload = { '__command__': True }
for val in obj.__slots__:
payload[val] = getattr(obj, val)
return payload
return super().default(obj)
def custom_command_decoder(obj):
if '__command__' in obj:
return CustomCommandEntry(**obj)
return obj
# the actual 'functional' parts
# this is the actual 'callback' that executes the custom command registered
# for 'sanity' sakes, custom commands cannot have arguments. Maybe I will
# modify it so they can in the future, but for now they don't.
async def custom_command_callback(entry, ctx, *args : str):
# in the entry content you can have ${user} and ${mention}
author = ctx.message.author
fixed = entry.content.replace('${user}', author.name).replace('${mention}', author.mention)
# find all ${N} and replace it with args[N]
def getter(obj):
try:
return args[int(obj.group(1))]
except:
return ''
fixed = re.sub(r'\${(\d+)}', getter, fixed)
await ctx.bot.send_message(ctx.message.channel, fixed)
class CustomCommand(commands.Command):
def __init__(self, **kwargs):
self._entries = {}
super().__init__(**kwargs)
async def invoke(self, ctx):
server = ctx.message.server
if server is not None:
entry = self._entries.get(server.id)
if entry is None:
return
# update the callback called
self.callback = functools.partial(custom_command_callback, entry)
self.params = inspect.signature(self.callback).parameters
await super().invoke(ctx)
# that ends the 'functionality'
bot = commands.Bot(command_prefix='>')
def register_custom_command(entry):
"""Registers a custom command to the bot."""
command = bot.get_command(entry.name)
if command is None:
# the command is not registered so we can add it
# for the first time using this entry as its first entry.
command = bot.command(name=entry.name, cls=CustomCommand,
pass_context=True, hidden=True)(custom_command_callback)
if not isinstance(command, CustomCommand):
raise RuntimeError('This is an already registered non-custom command.')
if entry.guild_id in command._entries:
# you can do some permission checking here, but this is outside the example's scope.
raise RuntimeError('This is already registered as a custom command.')
command._entries[entry.guild_id] = entry
def load_custom_commands():
try:
with open('custom_commands.json') as f:
entries = json.load(f, object_hook=custom_command_decoder)
for entry in entries:
register_custom_command(entry)
except FileNotFoundError:
pass
def save_custom_commands():
entries = []
for name, command in bot.commands.items():
if isinstance(command, CustomCommand):
entries.extend(command._entries.values())
with open('custom_commands.json', 'w') as f:
json.dump(entries, f, ensure_ascii=True, cls=CustomCommandEncoder)
@bot.event
async def on_ready():
print('logged on')
print('Name {0.name}\nID: {0.id}'.format(bot.user))
load_custom_commands()
print('loaded custom commands')
@bot.command(pass_context=True, no_pm=True)
async def create(ctx, name, *, content):
"""Creates a custom command for your server.
The following placeholders are available:
- ${user} : replaces the user's name
- ${mention} : replaced with a mention of the user
Custom commands are forced to be lower case.
"""
entry = CustomCommandEntry(name=name.lower(), content=content, guild_id=ctx.message.server.id)
try:
register_custom_command(entry)
except RuntimeError as e:
await bot.say('Error: ' + str(e))
else:
save_custom_commands()
await bot.say('Successfully registered command {0.prefix}{1}'.format(ctx, name))
# removing custom commands exercise to the reader.
bot.run('token')
@Miichel
Copy link

Miichel commented Mar 23, 2020

This doesn't work.

@9u3
Copy link

9u3 commented Apr 20, 2020

This doesn't work.

This isn't a rewrite version.

@9u3
Copy link

9u3 commented Aug 9, 2020

Working on a rewrite vers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment