So I'm trying to make a command that adds the name of a song to an user. I just don't understand how I should do that. I tried looking on the dictionary documentations but I couldn't find anywhere how I could append a variable to a certain person. This is my current code altough I think it's completely wrong:
#commands.command()
async def quote(self, ctx):
await ctx.send("add your quote")
msg = await self.client.wait_for('message', check=lambda message: message.author == ctx.author)
quote = msg.content
with open('quotes.json', 'r') as f:
quotes = json.load(f)
quotes.append(quote)
with open('quotes.json', 'w') as f:
json.dump(quotes, f)
await ctx.send("quote added!")
You can use this with a dictionary and track them by ID. Be careful with this, as JSON does not allow you to use integers as keys to anything. Only strings are allowed.
#commands.command()
async def quote(self, ctx):
await ctx.send("add your quote")
msg = await self.client.wait_for('message', check=lambda message: message.author == ctx.author)
quote = msg.content
with open('quotes.json', 'r') as f:
quotes = json.load(f)
strid = str(msg.author.id) # this is necessary for json
if strid not in quotes.keys():
quotes[strid] = []
quotes[strid].append('My quote, or put whatever you need to add in here')
with open('quotes.json', 'w') as f:
json.dump(quotes, f)
await ctx.send("quote added!")
As a sidenote, it's a bad idea to open the file and close it multiple times. Instead, you can try a construct like this, and then you will be spared from opening the file so much:
client = commands.Bot(...)
with open('quotes.json', 'r'):
client.quotes_data = json.load(f)
#tasks.loop(minutes=3.0) # adjust this at your liking, or execute it manually
async def save_all():
with open('quotes.json', 'w'):
json.dump(client.quotes_data, f)
save_all.start()
If you're trying to make it so users can request multiple songs in a queue type fashion, I'd create a dictionary, make the key the user (the message's author)'s ID (ctx.author.id) and set the value to an empty list, then append to that list the user's requested song's name.
On the other hand, if you prefer one song per user, just set the value to the song for the user's ID's key.
This would typically use just casual key assignments for dictionaries.
An example of how this would work (assume this is inside your command):
songs = {};
# This code if you'd like multiple songs per user.
songs[ctx.author.id] = [];
songs[ctx.author.id].append("SONG VALUE HERE");
# This code if you'd like one.
songs[ctx.author.id] = "SONG VALUE HERE";
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)
I am trying to create a command (<MF_add) that adds a point to member's json value and that only admins can use.
This is my code right now:
#client.command()
#commands.has_permissions(administrator = True)
async def MF_add(ctx, user: discord.Member):
with open ("MF Points.json", "r") as f:
users = json.load(f)
await client.get_user(user_id)
user = client.get_user(user_id)
if user in users:
users["{user.mention}"]["points"] += 1
await ctx.message.channel.send(f"You have given {member.mention} 1 MF point.")
with open("MF Points.json", "w") as f:
json.dump(users, f, indent = 4)
It's not giving any errors, but it's also completely unresponsive.
Thank you for any help!
First off I'd like to recommend you use SQLLite instead of JSON. JSON is not a database. You should really refrain from using it to store user data that can frequently change.
Regarding what you've currently got, JSON is used similar to a dictionary. It uses keys and values. I highly doubt that the if statement if user in users: is returning true. You should check (with a print statement) to see if the if statement is even working.
You don't actually make a command here, the #commands.has_permissions(administrator = True) is not what you use to make a new command. You need a #bot.command() in front of it like:
#bot.command()
#commands.has_guild_permissions(administrator=True)
async def MF_add(ctx, user: discord.Member):
with open ("MF Points.json", "r") as f:
users = json.load(f)
await client.get_user(user_id)
user = client.get_user(user_id)
if user in users:
users["{user.mention}"]["points"] += 1
await ctx.message.channel.send(f"You have given {member.mention} 1 MF point.")
with open("MF Points.json", "w") as f:
json.dump(users, f, indent = 4)
That would solve your question I believe, now to talk a bit about your program as it will not function like you expect it to, at all (or it'll just error):
client.get_user(userid) is not asyncronous and doesn't need to be awaited
you seem to never define user_id anywhere (as it is a variable)
why do you want to get the user again in the first place? You get the user from you parameters right?
["{user.mention}"] from when you look at the user's key is nothing but a string, you need to add an f in front of it for it to actually look for a mention value in user
ctx.message.channel.send can be shortened to ctx.send
f"You have given {member.mention} 1 MF point." You never defined a member value
I've rewritten most of your code into something that should work I believe:
#bot.command()
#commands.has_guild_permissions(administrator=True)
async def MF_add(ctx, user: discord.Member):
with open ("MF Points.json", "r") as f:
users = json.load(f)
if str(user.id) in users:
users[str(user.id)] += 1
else:
users[str(user.id)] = 1
await ctx.send(f"You have given {user.mention} 1 MF point.")
with open("MF Points.json", "w") as f:
json.dump(users, f, indent = 4)
Note that not knowing what you actually want to achieve with this code/what other functions you want to introduce I'm not too sure this is the best way. But you should be able to figure things out with this as a basis
Note: I converted the keys to strings as json doesnt like int keys, you can use int keys if you use a custom object_hook though (I'll let you look into that, it probs isnt work looking into for the use case you have anyways)
I want to make a list with a list of id discord servers that want to disable some of the functions of my bot.
For example: the on_member_join method will not send a message when a person enters the server, and on the other where this function is enabled, it will send that the person has connected to the server. But I don't know how to properly store the id and use it. At the moment there is this:
async def serverid(ctx):
sid = ctx.message.guild.id
await ctx.send(sid)
sid = 705735563696799723 (id server dependent)
that's roughly what I want to get in the end
async def test(ctx):
f = open('/app/commands/servers.txt', 'r')
servers_sid = f.readlines()
now_sid = ctx.message.guild.id
if now_sid == servers_sid: #i know servers_sid = ['id'] or something similar this is what i have a problem with
await ctx.send('Command disabled')
else:
#command execution
i know servers_sid = ['id'] or something similar this is what i have a problem with
You should use splitlines so that you will not carry the \n. I made the check to be not in if it is not in the file then it will just end
async def test(ctx):
with open('/app/commands/servers.txt', 'r') as f:
servers_sid = f.read().splitlines()
now_sid = str(ctx.message.guild.id)
if now_sid not in servers_sid:
await ctx.send('Command disabled')
return
await ctx.send('This is working')
#command execution
I am assuming you txt file is like this.
123
456
789
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.