Search code examples
pythonpython-3.xdiscorddiscord.pynextcord

Nextcord (discord.py fork) - How can I return to Discord that a command is currently running?


I have a Discord bot with a command that take some time to be completed (about 5 seconds). When the command take too much time to complete without any responses to Discord servers, I've seen that Discord make the command crash, and delete the Context, so when I send a response, it raises an error to say that the Context does not exists.

MEE6 by example, when executing a command, Discord returns: Sending command... And when MEE6 receive the command, it says: MEE6 is thinking... But my bot does not. How can I do like MEE6, return to Discord that my command is still running ?

Im using Nextcord (a discord.py fork) so discord.py anwsers will works too.

Minimal reproductible code:

import requests, nextcord
from nextcord.ext import commands

bot = commands.Bot(intents=nextcord.Intents.all())  # be sure to enable every discord intents in the discord dev portal

@bot.slash_command(name='axolotl')
async def axolotl(ctx):  # do things that take a lot of time
    r = requests.get('https://axolotlapi-test.kirondevcoder.repl.co/reddit?nsfw=0', timeout=2)
    if r.status_code == 200:
        data = r.json()['data'][0]
        embed = nextcord.Embed(title='Axolotl !', description=data['text'] or 'No text content.')
        medias = ""
        for media in data['media']:
            embed.set_image(media)
        await ctx.send('', embed=embed)
    else:
        await ctx.send('', embed=nextcord.Embed(title='Axolotl !', description='There was an error while contacting the API.'))


bot.run('your token here')

I know that the ctx object is not a nextcord.Context object but a nextcord.interaction.Interaction object and I think the API docs of this class can be found at https://docs.nextcord.dev/en/stable/api.html#nextcord.Interaction but im not sure.

I allready tried to make the bot typing on the channel, but it does not change anything:

@bot.slash_command(name='axolotl')
async def axolotl(ctx):
    async with ctx.channel.typing():
        r = requests.get('https://axolotlapi-test.kirondevcoder.repl.co/reddit?nsfw=0', timeout=2)
        if r.status_code == 200:
            data = r.json()['data'][0]
            embed = nextcord.Embed(title='Axolotl !', description=data['text'] or 'No text content.')
            medias = ""
            for media in data['media']:
                embed.set_image(media)
            await ctx.send('', embed=embed)
        else:
            await ctx.send('', embed=nextcord.Embed(title='Axolotl !', description='There was an error while contacting the API.'))

(I only provided the command code, else its the same code as the minimal reproductible code)

Can someone help please ?


Solution

  • If your commands take a while to execute then you can defer() to tell discord that your commands are going to take a while (and get the "Bot is thinking..." message).

    So add await ctx.response.defer() at the start of your command. You can then use the followup attribute to send a message and "respond" to the slash command.

    @bot.slash_command(name='axolotl')
    async def axolotl(ctx):
        await ctx.response.defer()
        async with ctx.channel.typing():
            r = requests.get('https://axolotlapi-test.kirondevcoder.repl.co/reddit?nsfw=0', timeout=2)
            if r.status_code == 200:
                data = r.json()['data'][0]
                embed = nextcord.Embed(title='Axolotl !', description=data['text'] or 'No text content.')
                medias = ""
                for media in data['media']:
                    embed.set_image(media)
                await ctx.followup.send('', embed=embed)
            else:
                await ctx.followup.send('', embed=nextcord.Embed(title='Axolotl !', description='There was an error while contacting the API.'))