I am writing a discord bot with discord.py.
I wrote an initial version but I decided it all needed reorganizing so I moved code to different files.
The code is all the same as it was before but now when I boot up the bot, the bot detects no messages being sent in any server unless the message came from the bot itself.
The main code that handles the client is:
import discord
import time
from command_list import *
from resource_functions import grab_setting_from_category
print("Main initialized")
client = discord.Client()
token = "BOT TOKEN"
prefix = "!"
#client.event
async def on_ready():
print("*** BOT IS READY ***")
async def server_count_loop():
while True:
servers = client.servers
await client.change_presence(
game=discord.Game(name=" in {0} Servers".format(str(len(servers)))))
time.sleep(10)
for server in client.servers:
for channel in server.channels:
if channel.name == "general":
await client.send_message(channel, content="Bot Online")
await server_count_loop()
#client.event
async def on_message(message):
print("Message detected from {0} as '{1}'".format(message.author, message.content))
if not message.author.bot:
global prefix
prefix = grab_setting_from_category(message.server.id, "server", "prefix")
if message.content.startswith(prefix):
for i in range(0,len(commands)):
key = list(commands.keys())[i]
table = list(commands.values())[i]
if message.content.startswith(prefix+key):
table["function"](message, commands)
client.run(token)
In the code there's the print(...) at the start of the on_message function which I am using as a basic way to let me know if the bot is detecting messages. The print statement prints whenever the bot sends a message in on_ready but no messages from other users on Discord are triggering the function.
Don't use:
time.sleep(...)
Instead, use:
await asyncio.sleep(...)
time.sleep is a blocking call, it blocks the asyncio loop to continue to run. That is why you need to have an asynchronous .sleep(...) method.
Related
I followed a tutorial to make add a basic music function to a discord bot, but it doesnt respond to any commands. I get the "henlo frens i is alieving" message as to indicate that the bot is ready, and there are no errors showing up. But then when i try to use the ping command i get no response, and nothing shows up in the terminal unlike the other bots i've written.
from plznodie import plznodie
from discord.ext import commands
import music
import time
#vars
cogs=[music]
intents = discord.Intents()
intents.all()
client = commands.Bot(command_prefix = "!" , intents=intents)
intents.members = True
activvv = discord.Game("you guys complain")
#config
for i in range(len(cogs)):
cogs[i].setup(client)
#client.event
async def on_ready ():
await client.change_presence(status = discord.Status.online, activity = activvv)
print("Henlo frens i is alieving")
#client.command()
async def ping(ctx):
before = time.monotonic()
message = await ctx.send("Pong!")
ping = (time.monotonic() - before) * 1000
await message.edit(content=f"Pong! `{int(ping)}ms`")
client.run("TOKEN")```
Don't change_presence (or make API calls) in on_ready within your Bot or Client.
Discord has a high chance to completely disconnect you during the READY or GUILD_CREATE events (1006 close code) and there is nothing you can do to prevent it.
Instead set the activity and status kwargs in the constructor of these Classes.
bot = commands.Bot(command_prefix="!", activity=..., status=...)
As noted in the docs, on_ready is also triggered multiple times, not just once.
I can further confirm this because running your code snippet (without on_ready defined) on my machine actually worked :
to process commands you need to add on_message function
#client.event
async def on_message(msg):
await client.process_commands(msg)
So, I'm using replit.com to make the bot, and the bot comes online just fine. I type in $hello and expect to get a response saying "Commander". I do that, but the bot doesn't reply back. I based this script off a video on Youtube. I'm guessing it could be something to do with my code, or the discord bot permissions. Any help/ advice would be appreciated, thanks.
import discord
import os
import time
client = discord.Client()
#client.event
async def on_ready():
print('We have broken into american server farms as {0.user}'.format(client))
time.sleep(1)
print("Accessing private data...")
time.sleep(2)
print("Installing malware...")
time.sleep(2)
print("Extracting stolen files...")
time.sleep(2)
print("Finishing up..")
time.sleep(1)
print("All objectives completed, State Messenger Bot is now online.")
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$hello'):
await message.channel.send('Commander')
client.run(os.getenv('TOKEN'))
I am not sure I fully understand the question but I will try to answer it
import discord
client = commands.Bot(command_prefix = '$')
#client.event
async def on_ready():
print("we have powered on, I an alive.")
#client.command()
async def hello(ctx):
await ctx.send('Commander')
client.run('TOKEN')
What the last part does is wait until someone says $hello and then replies Commander. The prefix has been defined at the start so you do not need to define a prefix for every command. In async def hello(ctx): you can change hello to be the name of your command
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)
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.
I think I'm doing something wrong. If I try to use to print a message in console it does work but if I try to send a message to discord I can't get it to work.
import discord
import asyncio
from discord.ext import commands
import schedule
import time
TOKEN = 'xxx'
client = commands.Bot(command_prefix = '.')
#client.event
async def on_ready():
print('Bot Online.')
async def job():
channel = client.get_channel('XXXX')
messages = ('test')
await client.send_message(channel, messages)
schedule.every(5).seconds.do(job)
while True:
schedule.run_pending()
time.sleep(1)
client.run(TOKEN)
I modified the code but I still get this message:
RuntimeWarning: coroutine 'job' was never awaited
self._run_job(job)
You need to use async on all functions, not just on the on ready. The function name is also called on_member_join.
#client.event
async def on_member_join(member):
await client.send_message(member, message)
The reason you have to dm the member and not send a message to a channel, is because no channel is specified.
Lets say you wanted to send a message to a specific channel you would have to do:
#client.event
async def on_member_join(member):
await client.send_message(client.get_channel('12324234183172'), message)
Replace the random number with the channel id.
If you want to read more about discord.py, you could read the docs or view a tutorial. Discord.py Docs
Note: Make sure to include import asyncio at the top of your page.
EDIT:
Another problem is that you did schedule.every(5).seconds.do(job). Change this line to: await schedule.every(5).seconds.do(job)