Export file asynchronously - python

I am trying to save a song edited using pydub in an await expression (because it's a Discord bot) but it always blocks the gateway and stops the bot from sending anything.
I tried
await song.export("audios/"+filename+".ogg", format="ogg")
but it gives me
TypeError: object _io.BufferedRandom can't be used in 'await' expression

Related

bot.get_channel() occasionally returning none in discord.py,

I am trying to write a discord.py bot. The following is an abridgement of my full code.
intents = discord.Intents.default()
intents.message_content = True
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(intents=intents, command_prefix="!", sort_commands=False)
client = discord.Client(intents=intents)
#bot.event
async def on_ready():
print(f'{bot.user.name} has connected to Discord!')
channel = bot.get_channel(12345678912345678912)
await channel.send("This is a test.")
bot.run(TOKEN)
Sometimes, the code above will work as intended, printing the connection message and sending the desired message into the target channel.
This is not always the case, however! I am getting an issue where the bot.get_channel() command returns none instead of the correct data. I assume this means that the channel cannot be found, except for the fact that the channel does exist.
The error that is sent to the console is;
AttributeError: 'NoneType' object has no attribute 'send'
I am very, very new to discord.py so I would appreciate any help I can get to better understand what's going on under the hood here. Thank you very much for your help.
The get_channel method is a cache lookup method, so it's not always reliable, or the bot doesn't have access to the channel, and since it doesn't raise an exception if the cache wasn't found and returns None instead, you can't know the reason for sure. You can use fetch_channel to make an API request after get_channel if it returns none; this method will raise an exception if the channel was not found or it doesn't have permission to fetch.
channel = (bot.get_channel(1234567890) or await bot.fetch_channel(1234567890))
await channel.send("This is a test.")
Also it seems like you have both discord.ext.commands.Bot and discord.Client instance, please choose one and remove the other.
The accepted answer is not recommended.
The reason it doesn't work is because the cache isn't populated yet in on_ready, but you should not make API requests (fetch_X & send) in on_ready! Making API calls in there has a high chance for Discord to just disconnect your bot.
Also, on_ready gets triggered multiple times, so you'll end up sending this message constantly even though you only started it once.
There's rarely a reason to do anything at all in there. If you want something to run once on startup you can create a Task & start it in setup_hook.

No errors outputing after i started using cogs in discord.py 2.0

After i rewritten my extension loading code in discord.py 2.0 everything works fine except if i got any errors in a command it will not send me a error. i have to figure it out with prints this is very annoying tho.
Is there a way to get the errors shown again, I got no error event or listeners
client = commands.Bot(command_prefix="!", intents=discord.Intents().all())
client.remove_command('help')
async def load_extensions():
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
await client.load_extension(f"cogs.{filename[:-3]}")
async def main():
async with client:
await load_extensions()
await client.start(tokn)
asyncio.run(main())
So after i deleted all cogs and nothing was loaded i still got no errors on anything, I also replaced the main function with client.run(token) itl run the bot but the cogs wont load but i get errors on command tho. anyone knows a fix?
The default behaviour was changed to use the logging framework instead.
Docs example & explanation: https://discordpy.readthedocs.io/en/latest/logging.html
Seeing as you're not using Client.run(), but rather Client.start(), there's no default handler being provided, so you have to do it yourself.
After following the example in the docs page linked above, your errors should get logged in a file named discord.log (or however you decided to name it).
If you'd like it to output to stdout (or stderr) like before, either do that manually in on_command_error(), or configure stderr as your handler for the logger instead of the RotatingFileHandler. This answer explains how to do that: https://stackoverflow.com/a/14058475/13568999

Verification system. (discordpy)

Okay so im trying to make a verify system, but im stuck with it. How could i fix it? (The reason for why i dont use simply ctx, is that this is in an on_ready event.)
guild = client.get_guild(id)
if client.fetch_guild(guild) == '928779004654256239':
channel = client.get_channel('930910261332819968')
text = discord.Embed(title="React below to verify.", color=discord.colour.blue())
moji = await client.send_message(channel, text, embed=text)
await client.add_reaction(moji, emoji='✔')
else:
return
Traceback:
C:\Users\User\Desktop\Dexton\Dexton.py:19: RuntimeWarning: coroutine 'Client.fetch_guild' was never awaited
if client.fetch_guild(guild) == '928779004654256239'
To answer your question, fetch_guild makes an API call and is a coroutine, so any calls to it should be awaited. It also accepts an int as a parameter, not a Guild, and you probably don't want to be comparing a Guild to an int either.
However, it seems that you're making unnecessary function calls anyway - you shouldn't need to call get_guild or fetch_guild at all. Just calling get_channel should be enough since the return type will be None if your bot account isn't in the guild anyway (as the channel won't be found).
With that in mind, you can change your code as such:
channel = client.get_channel(930910261332819968)
text = discord.Embed(title="React below to verify.", color=discord.Colour.blue())
if channel:
moji = await channel.send(embed=text)
await moji.add_reaction('✔')
A few other improvements were also made in the above code snippet, namely using TextChannel.send and Message.add_reaction in favor of Client.send_message and Client.add_reaction, respectively.
You should also keep in mind that a new verification message will be sent each time you run your bot unless you add a mechanism to prevent that. You may also want to use fetch_channel rather than get_channel to prevent any cache issues.

How does discord.py detect that a message is sent using just a coroutine which is being defined in the code itself?

I am a intermediate python programmer and just started coding discord bots using the discord.py module. One question that always revolves around my head is, how does the module detect that a message is sent using on_message() coroutine which is declared in our code and no such detection construct is there?
async def on_message(mssg):
#our conditions and responses
Consider the above code. Is there an equivalent predefined coroutine in the module that calls when we declare the on_message() in our code or is there something else that makes it to detect messages and pass it to the function argument, or detect any other event? On youtube or elsewhere, they just make you learn the syntax for some reason that you have to use async...await from the documentation.
so if memory serves me correct, the on_message() is what calls the bot to listen to each message that is sent, every time a message is sent. So with your code there:
async def on_message(mssg):
#our conditions and responses
we can actually dress that up a bit with some inter-workings, like so:
#bot.listen('on_message')
it's a bot event, so every-time a message is sent, this function is called.
async def stuff(message):
pass message so that the bot knows what to scan.
if message.content.startswith("buttlerprefix"):
start it off with an if statement so that the bot has something to check the user's message against
If I typed buttlerprefix and hit enter, it would respond with this message:
msg = await message.channel.send("my prefix is `>`")
if you want to go an extra step, and keep the channels declutterd, you can set the response equal to a variable msg in the event that you want to manipulate it later, thus in this scenario, it's set to auto delete with
await asyncio.sleep(10)
await msg.delete()
So if we put all of that together:
#bot.listen('on_message')
async def stuff(message):
if message.content.startswith("buttlerprefix"):
msg = await message.channel.send("my prefix is `>`")
await asyncio.sleep(10)
await msg.delete()
we get a function that is now scanning every message that comes through the guild that this bot functions in, no matter the channel, due to the on_message() function being called every-time a message is sent which is triggered by the #bot.listen

on_reaction_add not being run

I'm new to discord.py and trying to make a translator bot. When the user reacts with a certain flag, the bot translates it, but the event is never getting called hence I have no code to translate any messages yet. I know it's not getting called because the program isn't printing an 'x' to the console.
#client.event
async def on_reaction_add(reaction, user):
channel = reaction.message.channel
print('x')
await client.send_message(channel, '{} has added {} to the the message {}'.format(user.name, reaction.emoji, reaction.message.content))
await client.process_commands(reaction.message)
Probably a bit late to this thread but, the answer above is a valid answer. But you can also use on_raw_reaction_add which gets called even if the messages aren't in the Bot's cache.
Called when a message has a reaction added. Unlike on_reaction_add(), this is called regardless of the state of the internal message cache.
Documentation Link
Example:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
channel = await self.bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
user = await self.bot.fetch_user(payload.user_id)
emoji = payload.emoji
await channel.send("Hello")
There isn't much valid reason for why the event isn't registered/called.
One of which is stated in the docs: http://discordpy.readthedocs.io/en/async/api.html#discord.on_reaction_add. Try adding a reaction immediately to a message that is sent after the bot is online. Since messages sent before the bot is online will not be recognized by the bot (not in Client.messages).
if the message is not found in the Client.messages cache, then this
event will not be called.
Another possible reason is that this function was never defined before the client loop commenced. Verify your indentation. And/Or try placing the function directly under client = Bot(...), to check if this is the problem.
If neither of the aforementioned solves your problem, please post a minimal, complete, verifiable example (a short runnable code from top to bottom that indicates your problem).

Categories