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

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 ?

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.'))

Related

My discord.py bot does not read any messages

I was making another discord.py bot in replit (yes, i know replit isn't optimal, but it's a small bot, and replit can easily do everything i need from it), and followed the exact steps I used when making another bot of mine that works flawlessly. Then, i tested it, and nothing happened. I checked the code, nothing there, then the developer options, everything was fine, and the bot permissions. The bot was on administrator. On top of this, the bot kept showing up as offline in discord, even though the project was running just fine. The token is okay, and I even asked chat GPT multiple times, and nothing worked.
This is my code:
import discord
import os
from keep_alive import keep_alive
from datetime import datetime
import requests, random
time = datetime.now().strftime('%H:%M:%S')
timeSplit = time.split(":")
hoursFiltered = int(timeSplit[0]) - 8
minutesFiltered = int(timeSplit[1])
cstHoursFiltered = hoursFiltered + 2
estHoursFiltered = hoursFiltered + 3
cstHours = int(timeSplit[0]) - 2
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
wyvernID = 688807968120373319
reminding = 0
help = "LIST OF COMMANDS:\n%kat: gives you a random image of a cat\n%opendms: opens dms with the bot (it sends you a message)\n%kathelp: seriously?\n%pick: type this command followed with either 2 or 3 options seperated by spaces, and it will chose one. (ex: %pick kat cat) Make sure you do NOT end your message with a space.\n"
#client.event
async def on_ready():
print ('We have logged in as {0.user}'.format(client))
while True:
if int(cstHours) == 15 and int(minutesFiltered) == 30 and reminding == 1:
for i in range(3):
await client.get_user(wyvernID).send("Wake up pls :)")
#client.event
#client.event
async def on_message(message):
global reminding
if message.author == client.user:
return
if str(message.author) in ["Cheez#5224"]:
await message.channel.send("?")
if message.content.startswith("%kat"):
response = requests.get("https://api.thecatapi.com/v1/images/search")
cat = response.json()
catDict = dict(cat[0])
await message.channel.send(str(catDict['url']))
if message.content.startswith("%opendms"):
await message.author.send("Dms Are Open With Me")
if message.content.startswith("%kathelp"):
print(help)
await message.channel.send(help)
if message.content.startswith("%pick"):
pickrawlist = message.content.split(" ")
if len(pickrawlist) >= 3:
choice = random.randint(1, len(pickrawlist) - 1)
await message.channel.send(pickrawlist[choice])
else:
await message.channel.send("An Error Has Occured. Please make sure you have no less than 2 choices.")
if "kat" in message.content.lower():
await message.add_reaction("<:👍>")
try:
keep_alive()
client.run(os.getenv('TOKEN'))
except discord.errors.HTTPException:
print("\n\n\nBLOCKED BY RATE LIMITS\nRESTARTING NOW\n\n\n")
os.system("python restarter.py")
os.system('kill 1')
"keep_alive" and "restarter" work just fine, as I used the same code that worked in my other bot. To be clear, the project hosting is fine, but the bot appears offline in discord. I gave the bot every permission in discord developers, and there is NO ERROR. I know that the reading is the issue, becuase I made the project print a message when a message is sent, and nothing is printed. I honestly have no idea what's happening, and would like help. If anyone can help me, that would be much appreciated :)

Trying to use discord.py to make the bot send a message as the command originator

I'm trying to create a bot on discord to tag things with tone indicators (i.e., /s for sarcasm) This project started off as just a library but then I realized I could have it append the tone indicator to the end of the message by using it as an argument. However, I can only get the bot to send it as itself, which is disappointing because it interrupts the flow of conversations. I'm writing it using python. Here's my code:
import discord
from discord_slash import SlashCommand, SlashContext # Importing the newly installed library.
client = discord.Client(intents=discord.Intents.all())
slash = SlashCommand(client, sync_commands=True) # Declares slash commands through the client.
guild_ids = [guild id] # Put your server ID in this array.
#client.event
async def on_ready():
print("Ready!")
#slash.slash(name="j", description="joking", guild_ids=guild_ids)
async def j(ctx:SlashContext, message:str): # Defines a new "context" (ctx) command called "ping."
await ctx.respond(eat=True)
send_message = await ctx.send(f"{message} /j")
def check(message):
return message.author.id == ctx.author_id
try:
answer = await bot.wait_for('message', check=check, timeout = 60.0)
except asyncio.TimeoutError:
await ctx.send("You took to long to answer...", hidden=True)
else:
# do something with answer (convert to tone indicator)
pass
client.run("bot token")
I know I don't actually need any of the last part, but it was suggested to me as a work around to make it ID the user. It returns nothing. Anyone know how to make it send as the user who inputted the command, or mask itself as such?
You can use webhooks for this
#inside your command
guild = client.get_channel(ctx.channel_id)
if channel is None:
#error here
return
webhooks = filter(lambda x: x.user == client.user, await channel.webhooks()) #gets only webhooks created by us
if len(webhooks) == 0:
webhook = await channel.create_webhook(name='something')
else: webhook = webhooks[0]
await webhook.send(content, username=ctx.author.username, avatar = ctx.author.avatar_url
References:
Webhooks
getting webhooks
sending messages with webhooks
discord-slash get channel id

Cannot send message from console to discord

So I'm trying to send a message from the console to discord as if it were a /say command. Specifically I'm trying to input the channel id and a message, and get the bot to send it.
But when I run it no error appears, the bot goes online, and nothing is sent to the text channel
Here is my code:
import discord
from discord.ext.commands import Bot
TOKEN = open('token.txt').readline()
client = discord.Client()
bot = discord.ext.commands.Bot
channel_entry = input('ID: ')
msg_entry = input('Mensagem: ')
#client.event
async def send_channel_entry():
channel = client.get_channel(channel_entry)
await channel.send(msg_entry)
bot.run(TOKEN)
Of course nothing happens, because send_channel_entry is never called. Have you tried calling the command or activating it via Discord to see if it works?

Python Discord bot delete users message

I am working on a discord bot in python3 (discord.py 1.3.3, discord 1.0.1) and I have a need to delete a user message, but I can't figure out how to call the coroutine properly.
I have looked at some other threads, and tried reviewing the documentation (and the discord.py docs) but I haven't been able to figure it out.
Here's what I'm testing with:
import discord
from discord.ext import commands
TOKEN = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(command_prefix='!')
#bot.command(name='deleteme', help='testing command for dev use')
async def deleteme(ctx):
msg = ctx.message.id
print(f'DEBUG: message id is {msg}')
await msg.delete
# await ctx.delete(msg, delay=None) #nope
# await ctx.delete_message(ctx.message) #nope
# await bot.delete_message(ctx.message) #nope
# await command.delete_message(ctx.message) #nope
# await discord.Client.delete_message(msg) #nope
Running this returns the console debug message with an ID number, but the message isn't deleted. If I add a debug print line after await msg.delete it doesn't return. So this tells me where the script is hanging. That said, I still haven't been able to figure out what the proper command should be.
The bots server permissions include "manage messages"
In order to delete a message, you have to use the discord.Message object, for example, you would do:
await ctx.message.delete()
The delete() coroutine is a method of discord.Message

Discord.py, there is any method do edit a message send by a webhook?

I'm currently making a suggestion system but I have a problem, I don't know how to edit a message (embed) send by a webhook, here is my code:
async def suggestion(ctx):
async with aiohttp.ClientSession() as session:
webhook = Webhook.from_url('...', adapter=AsyncWebhookAdapter(session))
embed = discord.Embed(color=color)
embed.add_field(name="Nouvelle suggestion !", value=ctx.message.content.lstrip(f"{prefix}suggest"))
embed.set_footer(text=f"""{ctx.message.author} • {datetime.now().strftime("%d %b %Y %H:%M:%S")}""",
icon_url=str(ctx.message.author.avatar_url))
await webhook.send(embed=embed, username=ctx.author.name, avatar_url=ctx.author.avatar_url)
for adding reactions:
#bot.event
async def on_message(message):
if message.channel.id == 650397901893140481 and message.author.id not in [296687703851008002, 639138362673987584, 632575363830120448]:
await message.add_reaction("<:yes:710947936372129854>")
await message.add_reaction("<:neutral:710949706296983603>")
await message.add_reaction("<:no:710947944823652362>")
for editing the message:
#bot.command()
async def test(ctx, *args):
message = await ctx.channel.fetch_message(args[0])
embed = discord.Embed(color=color)
embed.add_field(name="Nouvelle suggestion !", value=args[1])
await message.edit(embed=embed)
error: discord.ext.commands.errors.CommandInvokeError: Command raised an exception: Forbidden: 403 Forbidden (error code: 50005): Cannot edit a message authored by another user
Perhaps this wasn't possible at the time you asked the question but it is now.
So for reference, an example how I do it in Ruby, no Python example available but it will be alike. The most important part is building the json and send it through the API.
require 'discordrb/webhooks'
SECONDEN = ARGV[0] || 3
WEBHOOK_URL = "your discord webhook url"
WAIT = true
client = Discordrb::Webhooks::Client.new(url: WEBHOOK_URL)
#my_builder = Discordrb::Webhooks::Builder.new
#my_builder.content = "test"
#my_builder.username = 'discordrb' # you can use whatever
message = client.execute(#my_builder, WAIT).body
message_id = JSON.parse(message)["id"]
while true
sleep SECONDEN
#my_builder.content = Time.now().strftime("%H:%M:%S")
RestClient.patch("#{WEBHOOK_URL}/messages/#{message_id}", #my_builder.to_json_hash.to_json, content_type: :json)
end
I made a library. a tool for discord webhooks
it called disWebhook
from DisWebhook import Message
url = "url"
# editing an existing message
mymsg = Message(url)
msg = mymsg.edit("Hello, World!")
print(msg)
# delete the message
#msg.delete()
EDIT: after researching. in discord.py docs
discord.Webhook
you can edit and delete like a normal message.
i didn't test the code but it's looks fine to me
# webhook
from discord import Webhook, AsyncWebhookAdapter
import aiohttp
import asyncio
async def foo():
async with aiohttp.ClientSession() as session:
webhook = Webhook.from_url('url-here', adapter=AsyncWebhookAdapter(session))
mymassge = await webhook.send('Hello World', username='Foo')
await asyncio.sleep(5)
await mymessage.edit(content="the new content of the message")
await asyncio.sleep(5)
await mymessage.edit(content="going to delete this message after 5")
await asyncio.sleep(5)
await mymassge.delete()
Apologies for the misinformation in my previous answer.
Webhooks don't have the ability to edit messages - they're only able to send them. This means that if you want to give the illusion that you've edited a message, you'll need to delete the message(s) and re-send them with the new content.
References:
discord.Webhook()
Discord docs - webhook - Specifically says they're a "low-effort way to post messages to channels in Discord", and nowhere does it talk about being able to edit messages.
Discord docs - editing messages

Categories