How to fix this problem discord.py bot problem - python

I created a bot in discord.py which works perfectly before i add a block of code. Once i added the code it stops working. Then i removed the newly added code. But my bot is not working now and sometimes it sends reply after 5 minutes but it doesn't shows any error. Then i created a new bot and pasted the token to check whether there is any problem with my code but it works perfectly.
i am wondering what is the problem bcs it didn't show any error and even with token as it prints in terminal too and even it sends reply to commands sometimes after 5 minutes. I regenerated the token of my bot even but now too the same problem is there.
Can someone say how to make my old bot to work properly? I don't want to start with new bot since my old bot is already in 86 servers and struggled hard to join it in that much servers.
from discord.ext.commands import Bot
from discord.ext import commands
import os
import discord
from random import randint
import keep_alive
import DiscordUtils
import random
from discord_components import *
# intents = discord.Intents.all()
intents = discord.Intents(messages=True, guilds=True,members=True,typing=True,presences=True)
bot = Bot(command_prefix="?", case_insensitive=True,intents=intents)
bot.remove_command("help")
global music
music = DiscordUtils.Music()
DiscordComponents(bot)
#bot.event
async def on_ready():
await bot.change_presence(status=discord.Status.idle, activity=discord.Game(f'on {len(bot.guilds)} servers | ?help'))
print(f"Logged in as {bot.user}")
#bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
title_error_one = 'You have not entered anything after the command'
desc_error_one = 'Use **?help** to see a list of all the commands available'
embed_var_one = discord.Embed(title=title_error_one,
description=desc_error_one,
colour=randint(0, 0xffffff))
await ctx.reply(embed=embed_var_one)
if isinstance(error, commands.MaxConcurrencyReached):
title_error_four = 'Someone is already playing'
desc_error_four = 'Please wait until the person currently playing is done with their turn'
embed_var_four = discord.Embed(title=title_error_four,
description=desc_error_four,
colour=randint(0, 0xffffff))
await ctx.reply(embed=embed_var_four)
if isinstance(error,commands.CommandOnCooldown):
embed = discord.Embed(
title="**Still on Cooldown!**",
description=f"Try again in {error.retry_after:.2f}s.",
colour=randint(0, 0xffffff)
)
await ctx.reply(embed=embed)
if isinstance(error, commands.CommandNotFound):
return
if __name__ == "__main__":
try:
for filename in os.listdir('./cogs'):
if(filename.endswith('.py')):
bot.load_extension(f'cogs.{filename[:-3]}')
except Exception as exc:
print(exc)
keep_alive.keep_alive()
token = os.environ.get("TOKEN")
bot.run(token)
This is the code on main.py file
I don't think other files have any errors. I only doubt with this file.
Thank you for help in advance
Atlast i found that it is due to on_member_update command. Once i commented it. My bot works fine(: and below is my on_member_update code. Is there anything Wrong or some way to make it fast. Below is the code
#commands.Cog.listener()
async def on_member_update(self,before, after):
try:
serverId=after.guild.id
channel_id=int(logs_info.find_one(
{'id': serverId})['action_logs'])
logchannel = self.bot.get_channel(channel_id)
except:
return
IST = pytz.timezone('Asia/Kolkata')
time_now = (datetime.now(IST))
time_now = str(time_now.strftime('%Y-%m-%d %H:%M:%S'))
if len(before.roles) < len(after.roles):
new_role = next(role for role in after.roles if role not in before.roles)
embed=discord.Embed(title=f"Roles given",description=f"{after.mention} has been given {new_role.mention} role",colour=randint(0, 0xffffff))
embed.add_field(name="Role added at",value=time_now)
elif(len(before.roles) > len(after.roles)):
new_role = next(role for role in before.roles if role not in after.roles)
embed=discord.Embed(title=f"Removed",description=f"{new_role.mention} role has been removed from {after.mention}",colour=randint(0, 0xffffff))
embed.add_field(name="Role removed at",value=time_now)
else:
return
embed.set_thumbnail(url=after.guild.icon_url)
embed.set_footer(text=self.bot.user.name,icon_url=self.bot.user.avatar_url)
embed.set_author(name=after.name, icon_url=after.avatar_url)
await logchannel.send(embed=embed)

Problem explanation
You use pymongo library to fetch some data in your on_member_update event:
channel_id=int(logs_info.find_one({'id': serverId})['action_logs'])
It's so bad because pymongo is a blocking library. It means that when you interact with your database this library blocks other code. Therefore your bot is so slow. It can't process command while it waits for pymongo request.
Solution
You can use motor instead of pymongo. It's an asynchronous wrapper for pymongo and it is related to this. But motor doesn't block your code execution.

Related

How can I make my Discord Bot delete all messages in a channel?

I am trying to make my bot delete all messages at once when a user asks the bot to do so, but my code isn't working.
import os
import discord
client = discord.Client()
client = commands.Bot(command_prefix='+')
#client.command(name='effacer')
async def purge(ctx):
async for msg in client.logs_from(ctx.message.channel):
await client.delete_messages(msg)
await ctx.send("Who am I? What is this place? And where the hell did the messages go?")
client.run(TOKEN)
How can I fix my code so that my bot can delete all messages? I believe my biggest problem is await client.delete_messages(msg), since Python continuously says that the client has no attribute to delete_messages.
By deleting every message would rate limit the bot, creating performance issues which would also slow down the bot. Instead it would be more efficient if the bot just deleted the channel and made a clone of it in the exact same place.
Here's the purge included in your command
#client.command(name='effacer')
async def purge(ctx):
await ctx.channel.delete()
new_channel = await ctx.channel.clone(reason="Channel was purged")
await new_channel.edit(position=ctx.channel.position)
await new_channel.send("Channel was purged")
So the way you would do that is with purge, not delete messages. This will delete all the messages in the channel AND keep the channel id the same, meaning you'll only need the manage_messages permission to run this command. The way it works is it counts all the messages in the channel and then purges that number of messages
import os
import discord
client = discord.Client()
client = commands.Bot(command_prefix='+')
#client.command(name='effacer')
async def purge(ctx):
limit = 0
async for msg in ctx.channel.history(limit=None):
limit += 1
await ctx.channel.purge(limit=limit)
client.run(TOKEN)

How to execute a python discord bot function in another python script?

I am trying to create a python script that would mute the users of a specific voice channel when executed. Till now I am able to mute everyone by typing the command in the discord text channel, but I would like to mute everyone when another python script tells the bot to. Below is my attempt to do that.
bot.py is the python discord bot:
import discord
from discord.ext import commands
from time import sleep
client = commands.Bot(command_prefix="./")
#client.event
async def on_ready():
print("Bot is online. ")
#client.command()
async def play_music_test():
channel = await client.get_channel(voice_channel_number)
voice = await channel.connect()
await voice.play(
discord.FFmpegPCMAudio(executable="C:/Users/USER/ffmpeg/bin/ffmpeg.exe",
source="C:/Users/USER/Desktop/song.mp3"))
client.run(TOKEN)
abc.py is the other python script trying to call a function:
from bot import play_music_test
import asyncio
print("")
asyncio.run(play_music_test())
I ran the bot.py first and then tried to execute the abc.py next, bot came online but when executing abc.py, it didn't print or do anything at all. I just started to learn discord.py so if this is a silly question, forgive me.
Instead of running the python file you can import it, or making it a cog
heres an example:
importing: bot.py
import discord
from discord.ext import commands
from time import sleep
from abc import *
client = commands.Bot(command_prefix="./")
#client.event
async def on_ready():
print("Bot is online. ")
#client.command(name = "play_music", aliases = ["you can asign aliases like this", "multiple ones too"])
async def play_music_test(ctx, channel): # If the python file doesn't know what channel is, it can be asigned when calling the function in discord, think of it like sys.argv or argparse
if channel == None: channel = ctx.channel # This sets the current channel you are in if none was provided when executing it in discord
# channel = await client.get_channel(channel) now you don't need this line
voice = await channel.connect()
await voice.play(
discord.FFmpegPCMAudio(executable="C:/Users/USER/ffmpeg/bin/ffmpeg.exe",
source="C:/Users/USER/Desktop/song.mp3"))
client.run(TOKEN)
importing: abc.py
remove asyncio.run(play_music_test())
use it in discord instead! ex. play_music_test #general
Making it a cog: bot.py
import discord
from discord.ext import commands
from time import sleep
import os
client = commands.Bot(command_prefix="./")
#client.event
async def on_ready():
print("Bot is online. ")
for filename in os.listdir("./"):
if filename == "bot.py": continue
else: client.load_extension(f"cogs.{filename[:-3]}")
client.run(TOKEN)
Making it a cog: abc.py
from bot import play_music_test
import asyncio
class Mycog(commands.Cog):
def __init__(self, client):
self.client = client
#client.command(name = "play_music", aliases = ["you can asign aliases like this",
"multiple ones too"])
async def play_music_test(ctx, channel): # If the python file doesn't know what
channel is, it can be asigned when calling the function in discord, think of it like sys.argv or argparse
if channel == None: channel = ctx.channel # This sets the current channel you are in if none was provided when executing it in discord
# channel = await client.get_channel(channel) now you don't need this line
voice = await channel.connect()
await voice.play(
discord.FFmpegPCMAudio(executable="C:/Users/USER/ffmpeg/bin/ffmpeg.exe",
source="C:/Users/USER/Desktop/song.mp3"))
def setup(client):
client.add_cog(Mycog(client))
This anwser is not the best but hope this helps!
i'm not sure, if i really understand, what you try to do, but to open a script from another script, i use subprocess.Popen()
but i think, in your case it fits more, to change the way you try to solve your problem. maybe you should take a look into the on_message event and use message.content
?
You can importing your client variable (from bot import play_music_test, client) and then client.loop.create_task(play_music_test())
(Although I do not understand why you would do such a thing)

Why won't Discord bot recognize commands?

I'm making a bot for a pokemon server, and I'm trying to make a command that will give the 'Gym Leader' role to another user. I try using the command, and using the test command, but there is no response in the server nor the shell.
import os
import discord
from dotenv import load_dotenv
from discord.ext import commands
from discord.utils import get
bot = commands.Bot(command_prefix='b!', case_insensitive=True)
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
client = discord.Client()
#client.event #works
async def on_ready():
print(f'{client.user.name} has connected to Discord!')
channel = client.get_channel(697500755766018098)
#client.event #works
async def on_member_join(member):
await member.create_dm()
await member.dm_channel.send(
f'Hi {member.name}, welcome to Pokémon Beast Ball!\n\nThis server utilizes Pokecord and Mewbot.\n\nSay \'pkhelp\' in the server to learn about Pokecord commands.\nSay \';help\' in the server to learn about Mewbot commands.'
)
#bot.command() #doesn't work
async def test(ctx):
print("test recieved")
await ctx.send(ctx)
#bot.command(pass_context=True) #this is the command that really needs help
async def newleader(ctx: discord.User=None):
print("command recieved")
if not user:
await ctx.send("Invalid")
print("1")
else:
role = discord.utils.get(ctx.guild.roles, name="Gym Leader")
role2 = discord.utils.get(ctx.guild.roles, name="Purple UniTurtle Man")
if role in ctx.author.roles or role2 in ctx.author.roles:
print("2")
await ctx.send(f'A new Gym Leader has been appointed')
await user.add_roles(role)
await bot.remove_roles(ctx.author, role)
else:
print("3")
await ctx.send("You do not have permission to use this command")
client.run(TOKEN)
You are mixing bot and client and your client = discord.Client() is stepping on your bot = commands.Bot(...) statement. Since you want to do commands and events you only use the commands.Bot(...) statement.
Remove the client = discord.Client() statement and change your #client.event decorators to #bot.event.
Also if you want to reference the command context in your test command update it with the ctx parameter async def test(ctx):.
That will get you started using your commands and entering b1test will now work.
Please note that the case_insensitive=True on the commands declaration refers to the command name and not the prefix.
Did you check :
bot connection → make a "on_connect" event (not exactly the same as "on_ready") to see if your bot successfully connect to your server (before receiving data from discord). If not, try to add your bot again to your server and check if all tokens are goods.
bot permissions (if your bot have the right to write in channel, read messages from channels, manage roles) → if your bot cannot read messages, he can't read commands !
role priority (you can't manage roles highers thant yours) → go to "server settings" > "roles" > put your bot role above the 'Gym Leader' role (or at the top of the list if you don't care).
The problem isn't actually what the selected answer suggests. There is probably no reason to use both commands.Bot and discord.Client but using both won't lead to that issue.
The issue is because you are only running the client, not the bot. You need to also run the bot instance if you want it to function.
If you are not trying to do something specific, then just using either bot or client will suffice anyway, so that part of the selected answer was helpful in avoiding the issue at least.

Discord py bot not triggering on_member_join function [duplicate]

This question already has answers here:
discord.py: Why isn't my join message working?
(2 answers)
Closed 2 years ago.
My discord py bot wont trigger the "on_member_join" event. Everything else works fine. I have other event methods that trigger normally. What am i doing wrong here? It doesnt even print the console statement when people join.
# Libs
import discord # Version 1.2.5
from discord.ext import commands
# set discord API token
token = "MASKED"
# Initiate used objects
bot = commands.Bot(command_prefix="!")
#bot.event
async def on_member_join(member):
print(f"{member} has joined the server.")
for channel in member.server.channels:
if str(channel) == "general":
await bot.send_message(f"""Welcome to the server
{member.mention}""")
bot.run(token)
If im right the problem is the user joined before your bot gets on.
Assuming you are using your alternate account to join your server for testing,
you should try printing a message after the bot gets on and then join the server.
You can do that by the following code.
https://discordpy.readthedocs.io/en/latest/api.html#discord.on_ready
#prints 'logged on' when bot is ready
#bot.event
async def on_ready():
print('logged on')
So after logged on was printed you can then join the server and see if it works.
I hope this solves you problem!
from discord.ext.commands import Bot
from discord.ext import commands
import asyncio
import time
import random
from discord import Game
Client=discord.client
client=commands.Bot(command_prefix='^')
Clientdiscord=discord.Client()
client.remove_command("help")
#client.event
async def on_member_join(member):
print(f'Recognised that a member called {member} joined')
await member.send(".")
print('Sent message to ' + member.name)
this is the script I use,I've added the topmost part of my bot to show where it goes.

The channel provided must be a voice channel. error with move_member

import discord
from discord.ext import commands
from discord.ext.commands import Bot
import asyncio
import time
bot = commands.Bot(command_prefix='$')
#bot.event
async def on_ready():
print ("Ready")
#bot.command(pass_context=True)
async def Move(ctx):
#channel to move to '414543063575429131'
#user to move '192361974053470208'
await bot.move_member('192361974053470208', '414543063575429131')
print("done")
bot.run("token_here")
This is my code but I when I try to move the user it gives me the error "The channel provided must be a voice channel."
I know the bot works because I had some simple commands earlier that would reply to messages earlier and they worked fine.
I am new to python and discord bots so I don't really know what to do. Any help is appreciated.
The channel argument to move_member must be a Channel object, not just the channel id. This is noted in the documentation for move_member
You cannot pass in a Object instead of a Channel object in this function.
#bot.command(pass_context=True)
async def move(ctx):
destination = '414543063575429131'
user = '192361974053470208'
await bot.move_member(ctx.message.server.get_member(user), bot.get_channel(destination))
# The get_member doesn't look to be strictly necessary, but it doesn't hurt
# and improves readability
print("done")

Categories

Resources