The problem is I want to dynamically change my prefix with a command. The prefix gets updated in the json file but the only problem is that the bot needs to reload to accept the new prefix. So I need a way to make the bot read the new prefix instantly after updating it in the config.json.
JSON FILE:
"command_prefix": "."
UPDATE PREFIX CMD: (The command is in my core cog)
# PREFIX CHANGE COMMAND
#commands.group(name="prefix", invoke_without_command=True)
#commands.has_permissions(administrator=True)
async def prefix(self, ctx):
current_prefix = get_config_file("command_prefix")
await ctx.channel.send(f'Current prefix is: **{current_prefix}** \n If you want to change the prefix use subcommand: _set_')
#prefix.command(name="set")
#commands.has_permissions(administrator=True)
async def set(self, ctx, mode):
mode != None
with open('config.json', 'r') as f:
config = json.load(f)
config["command_prefix"] = mode
with open('config.json', 'w') as f:
json.dump(config, f, indent=4)
f.close()
await ctx.channel.send(f'Prefix has been changed to `{mode}`')
When you first initialize a bot, it creates a prefix and uses that prefix only until you recreate the bot. If you want the bot to have a different prefix or update it, you need a callback on the command_prefix argument.
First create the get_prefix function.
async def get_prefix(bot, message): # you can also do it by guild with message argument
return get_config_file("prefix_command")
then in the Bot instance
bot = commands.Bot(command_prefix=get_prefix)
Note: These both will be in the main file where you create the bot. It will change immediately every time you update the prefix.
Related
async def on_message(self, message):
if message.author == self.user:
return
if message.content.lower() == 'hi':
await message.channel.send('hello')
if message.content.lower() == '':
f = open("Path/To/Your/File.txt", "w") # 'r' for reading and 'w' for writing
f.write("" + f.name) # Write inside file
f.close()
If someone sends a message in a discord channel, and the message does not contain the word, "hi", I want it to save the unknown message into an existing text file. Without using client commands or code.
I know you asked not to receive code, but I am going to have to.
This portion:
if message.content.lower() == '':
f = open("Path/To/Your/File.txt", "w")
f.write(""+f.name)
f.close()
Seems to check if a user sends a blank message (should be impossible, since you have to send some thing in discord), and opens Path/To/Your/File.txt in write mode, and writes in the name of it (File.txt). Also, lower() makes the text lowercase, and that is not needed since you cant have an uppercase nothing.
Also, the Path/To whatever means you would have to create three folders, path, to, and your, and then put a File.txt in your. You should put a file.txt in your current folder, and change that /Path/To to just file.txt.
It does not check if the bot does not have a response.
You should completely remove that section.
Step 1:
Create a file called like log.txt.
Step two:
Replace that section of code with:
#checks if the bot has a response
knownmessages = ["hi"] #you can add more
if message.content not in knownmessages:
f = open("log.txt", "a") #or what you called it. also a for append, it would overwrite otherwise.
f.write(message.content + "\n") #\n means new line
f.close()
You seem to be a beginner, so don't worry. I remember when I was a beginner.
According to your comment, I think you want to log the messages to a text file only if the bot does not have a response for it.
So here's how you could structure your on_message function:
Define the function as async def on_message(self, message)
After this you can check if you sent the message:
if message.author == self.user:
return
Then you can add specific responses for specific strings:
if message.content.lower() == "hi":
await message.channel.send("hello")
return
Now's where the important part comes in:
First you create a context by using self.get_context(message)
After this you have to check if the context can be used to invoke a command. If yes, then the context is valid, and you can invoke the command.
If the context is invalid, then you can log the contents to a file.
if context.valid():
await self.invoke(context)
return
If none of these if clauses trigger, then that means the bot does not have a reponse for the message. So you can log it to the file.
with open("path/to/file.txt", 'a') as f: # a for append
f.write(message.content + '\n')
So your final on_message method will be:
async def on_message(self, message):
# Check if the bot sent the message.
if message.author == self.user:
return
# Reply to some predetermined strings of text
if message.content.lower() == "hi":
await message.channel.send("hello")
return
# Create a context from the message
context = await self.create_context(message)
# If the context is valid, then invoke the command
if context.valid:
await self.invoke(context)
return
# Append to file if the bot does not have a respone to the message
with open("path/to/file.txt", 'a') as f:
f.write(message.content + '\n')
Sorry for the unclear question title. I don't know any other way to put it.
I made a command that says p!channel [channel_id] which basically makes a channel where my bot will respond with "e". I want the command to store the channel_id and guild_id into a json file called channel.json, and when a user sends a message, it will check if the message is in the channel_id channel, and if it is in the channel, will send "e". However, it's not responding and no error codes are showing up. Can someone help? Code is below:
def get_channel(client,message):
with open("channel.json", "r") as f:
e = json.load(f)
return e[str(message.guild.id)]
#client.command()
#commands.has_permissions()
async def channel(ctx, *, channelid):
with open("channel.json", "r") as f:
e = json.load(f)
e[str(ctx.guild.id)] = channelid
with open("channel.json", "w") as f:
json.dump(e,f)
await ctx.send(f"Successfully setup <#{channelid}>")
#client.event
async def on_message(message):
if message.channel.id == get_channel:
await message.channel.send('e')
There are several immediate problems that are keeping this from functioning.
You're only referencing get_channel, not calling it. The channel's ID isn't equal to the function itself, so the message is never sent. You want get_channel(client, message).
Your on_message event ensures that your command never gets called.
You attempt to use ctx.send() instead of ctx.channel.send().
Channel IDs are integers, but command arguments are always read in as strings. Without converting the argument to an integer, comparing it against a channel's ID will always return False.
In addition, there are several things you could improve:
The get_channel function doesn't ever use client, so you could alter your function definition to simply get_channel(message).
Furthermore, channel IDs are globally unique, so you don't need to save the guild ID in order to unambiguously identify a channel.
It would be more efficient not to read the whole file every time you need to check for an ID.
The has_permissions check doesn't check anything if you supply it no arguments, so in your code it does nothing.
You probably don't want your bot to respond to its own messages.
Here's an improved version that reads a saved file on startup, if one exists. It then keeps the IDs as a set in memory, and only opens the file when it needs to add a new ID.
from discord.ext import commands
import json
client = commands.Bot(command_prefix='p!')
try:
with open('channels.json') as f:
client.ids = set(json.load(f))
print("Loaded channels file")
except FileNotFoundError:
client.ids = set()
print("No channels file found")
#client.command()
async def channel(ctx, channel_id):
try:
channel_id = int(channel_id)
except ValueError:
await ctx.channel.send("Channel must be all digits")
return
if channel_id in client.ids:
await ctx.channel.send(f"Channel <#{channel_id}> is already set up.")
return
client.ids.add(channel_id)
with open('channels.json', 'w') as f:
json.dump(list(client.ids), f)
await ctx.channel.send(f"Successfully set up <#{channel_id}>")
#client.event
async def on_message(message):
if message.channel.id in client.ids and message.author != client.user:
await message.channel.send('e')
# Pass processing on to the bot's command(s)
await client.process_commands(message)
client.run(TOKEN)
This question already has answers here:
Why does on_message() stop commands from working?
(2 answers)
Closed 1 year ago.
I wanted to make my Discord Bot have changing prefixes. By this is I mean the user (has to have administrator permissions) sets the prefix as they want it to be. The default prefix is & but say if they want it to be ! they would use the &spr command, like this &spr ! and the prefix would be changed to !. That in itself works fine. However, for that to work, it needs a starting prefix so I set it up like this:
#client.event
async def on_guild_join(guild):
with open('prefixes.json', 'r') as pr:
prefixes = json.load(pr)
prefixes[str(guild.id)] = '&'
with open('prefixes.json', 'w') as pr:
json.dump(prefixes, pr, indent = 4)
It writes to a json file when the bot joins the server like this:
{
"SERVER1 ID": "&",
"SERVER2 ID": "&",
"SERVER3 ID": "&",
"SERVER4 ID": "&",
"SERVER5 ID": "&"
}
I also have a function, at the start of the code, that retrieves the prefix :
def getPrefix(client, message):
with open('prefixes.json', 'r') as pr:
prefixes = json.load(pr)
return prefixes[str(message.guild.id)]
and gives it to the client:
client = commands.Bot(command_prefix = getPrefix, help_command = None)
Everything works fine. However, I realised that because it adds the prefix to the json file when it joins the server, it doesn't add it if the bot joins the server while it's offline. This means that the bot can't respond to any commands since it doesn't have a prefix. To combat this, I created a setup event:
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('&setup'):
with open('prefixes.json', 'r') as pr:
prefixes = json.load(pr)
prefixes[str(message.guild.id)] = '&'
with open('prefixes.json', 'w') as pr:
json.dump(prefixes, pr, indent = 4)
It adds the prefix & to the json file as planned. However, the bot still doesn't respond to commands even though it has its prefix set in the json file. How can I make it work?
When you use the on_message event, you have to always remember to add the process_commands function, like so:
#client.event
async def on_message(message):
#Do Something
await client.process_commands(message)
What im trying to do: I have a custom prefix system similar to this one: discord.py prefix command And this is my event for when my bot is mentioned:
#client.event
async def on_message(message):
if client.user.mentioned_in(message):
embed=discord.Embed(title=f"Hello! my prefix is `{prefix}`")
await message.channel.send(embed=embed)
await client.process_commands(message)
So i want my bot to respond with the prefix for that server.
My problem: I don't know how i can read the json file and get the prefix.
To add custom prefixes to your bot, you can store the prefix data in a JSON file. You should create a file named prefixes.json and 3 commands/events: An event to set a default prefix when the bot joins a server, an event to remove the prefix information from the prefixes.json file, and also a command to change the bot's prefix.
Here is how you can write the first event: the event that defines a default prefix when the bot joins a guild:
#client.event
async def on_guild_join(guild):
with open('prefixes.json', 'r') as f:
prefixes = json.load(f)
prefixes[str(guild.id)] = 'GG'
with open('prefixes.json', 'w') as f:
json.dump(prefixes, f, indent=4)
And this is a way you can write the event to remove the prefix data from the JSON file when the bot is removed from a server:
#client.event
async def on_guild_remove(guild):
with open('prefixes.json', 'r') as f:
prefixes = json.load(f)
prefixes.pop(str(guild.id))
with open('prefixes.json', 'w') as f:
json.dump(prefixes, f, indent=4)
And finally, here is how you can define the function to change the prefix of the bot. The command will be named changeprefix, and you can use it by typing [prefix]changeprefix ( replace [prefix] to your bot's prefix ). :
async def changeprefix(ctx, prefix):
with open('prefixes.json', 'r') as f:
prefixes = json.load(f)
prefixes[str(ctx.guild.id)] = prefix
with open('prefixes.json', 'w') as f:
json.dump(prefixes, f, indent=4)
You'll also need a command to find the prefix corresponding to the guild your bot is in. It's a simple function you can define just like this:
def get_prefix(client=None, message=None):
with open('prefixes.json', 'r') as f:
prefixes = json.load(f)
try:
prefix = str(message.guild.id)
return prefixes[prefix]
except AttributeError:
return ['defaultPrefix']
Now, the last step to this is to integrate those four commands into your bot variable you defined to run other commands. Here is how you should change the prefix statement:
client = commands.Bot(command_prefix=get_prefix)
This is the code:
#bot.command(name="add")
async def _blacklist_add(self, user: discord.Member):
"""Adds user to bot's blacklist"""
if user.id not in self.blacklist_list:
self.blacklist_list.append(user.id)
fileIO("blacklist.json", "save", self.blacklist_list)
await self.bot.say("User has been added to blacklist.")
else:
await self.bot.say("User is already blacklisted.")
#bot.command(name="remove")
async def _blacklist_remove(self, user: discord.Member):
"""Removes user to bot's blacklist"""
if user.id in self.blacklist_list:
self.blacklist_list.remove(user.id)
fileIO("blacklist.json", "save", self.blacklist_list)
await self.bot.say("User has been removed from blacklist.")
else:
await self.bot.say("User is not in blacklist.")
I want to know how to import JSON so that I can stop use abusing my bot, if you can help me.
You can use the json module.
Assuming you have a file in the same directory as your bot (named "ids.json"), which you want to load the IDs from:
import json
with open("ids.json", "r") as f:
ids = json.load(f)
All you need to put in the "ids.json" file is
["249928002161344512", "387539916525142016", "359951141343068182", "308293489827774465"]
You are now free to use the ids variable in the same way as you are now.
If you want to save the content of the ids variable to the file, you can use json.dump(ids, f)
with open("ids.json", "w") as f:
json.dump(ids, f)
However, you do need to be careful of using the file too much. Dumping a lot can cause issues where data is not saved to the file properly.