Using a mention as an input to a command - discord.py

I'm trying to create a command for my bot that will go through and remove a specified number of messages from the mentioned user, the command syntax is .cleanfrom <#user> <numberOfMessages>.
in order to see how I can identify a user from a mention, I tried printing the input for the name like so.
#client.command(aliases=['cf'])
async def CleanFrom(ctx, user, count=5):
print(user)
but it just returns None.
How can i use a mention as an input for a command?

I'm not sure why it returns None but in order to get discord.Member object from an argument, you can use converters.
#client.command(aliases=['cf'])
async def CleanFrom(ctx, user: discord.Member, count=5):
...
This will return you a discord.Member object.

Related

Cant get user name discord.py

I am making a bot for my favorite twitch streamer and medium length story short, I need a profile function for the bot. It works when you don't # someone in the second argument, but I want people to be able to see another users profile.
async def profile(ctx, user=None):
if user:
user = discord.User.display_name
else:
user = ctx.message.author.name
with open('users.json', 'r') as f:
file = json.load(f)
await ctx.send(f'PP: ``{file[user]}``')
users.json looks like this:
Your code at its current stage is quite confusing. Let me explain:
You have no method of properly accessing your user, instead calling an empty object.
You're using two separate ways to get the name, via name and display_name, which are two separate names. Adding to this, this method does not take into account that two users may have the same name.
You can define discord.Member within the command itself. If there is no user mentioned, this will default to the command author, ctx.author (which is the same as ctx.message.author).
In the code below, you will notice two ways of I have defined the variable user_info. If you're going to access the numbers based on a discord user's name, I would highly recommend replacing the name with the user id so you can access other discord user information via get_member or similar. Otherwise, feel free to continue using user.name.
Do view the revised code below.
async def profile(ctx, user:discord.Member=None):
if not user:
user = ctx.author
# either continue to save with the name..
user_info = user.name # or user.display_name but don't use both!
# ..or save with their user id
user_info = str(user.id)
with open('users.json', 'r') as f:
file = json.load(f)
await ctx.send(f'PP: ``{file[user_info]}``')

How to pass the user invoking command as default parameter in discord.py bot.command?

I am trying to make a rank based system for my discord.py bot.
I want to implement a rank command which returns the rank of the specified user. By default I want the specified user to be the one invoking the command, i.e. ctx.message.author.
async def rank(self, ctx, user: discord.Member=ctx.message.author):
I know this is invalid syntax, but how could I achieve such a thing?
My discord.py version is 1.7.3.
Thanks!
I would make user default to None (using typing.Optional) and replace it with ctx.message.author inside the command.
e.g
async def rank(self, ctx, user: typing.Optional[discord.Member]=None):
if not user:
user = ctx.message.author

How can I make it so only a certain role can use a command with discord.py?

I'm attempting to make a command that only works with a certain role. I'm not 100% sure how to do this and I cannot find a solution anywhere else. My code stops short because I'm not very familiar with coding quite yet, but here it is:
#bot.command()
async def sign(ctx, member: discordMember):
if ctx.author.server_roles
From here I am completely lost and have no idea what to do.
The most efficient way to make it so a command can be used only with a certain role is the .has_role() decorator. You may put there a string with the role name (case sensitive) or the role ID (recommended), more info can be found in the documentation Here is an example:
#bot.command()
#commands.has_role("Administrator")
async def foo(ctx)
await ctx.send("bar")
If you would like to make it so the user can use this command only when he has any role then .has_any_role() would be the way to go, it takes strings or integers as well. You can find more info on it here. Here is a quick example on how that would work:
#bot.command()
#commands.has_any_role("Administrators", "Moderators", 492212595072434186)
async def foo(ctx):
await ctx.send("bar")
Happy Coding!
Usually when someone tries to execute such command with a .has_role decorator the discord.ext.commands.MissingRole is raised, so handling it would be something like this :
#bot.command()
#commands.has_any_role("Administrators", "Moderators", 492212595072434186)
async def foo(ctx):
try:
await ctx.send("bar")
except commands.MissingRole:
await ctx.send("lol")
Of course if you have a lot of commands, then I would recommend using a global error handler.

I have problems with command that gets what user typed after command

I am doing a Discord Bot for one SandBox page.
I have already made a program that scraps the data from ANY user you want it to. (It's input and after that it scraps the data)
Now there is a new problem. I want to make a command "rr2.info.UserHere"
The rr2. is prefix, but I want to make a command that gets what you typed after rr2.info. and saves it into a variable.
I have tried with some code I found online, but it wasn't working. After that I couldn't find ANYTHING else.
#client.event
async def on_message():
if message.content.startswith('rr2.info.'):
#This is the part I need help with! :D
I need a way of getting ANYTHING typed after rr2.info. and that command done!
It's not a good practice to use the on_message() as commands.
Better use command() fom discord.ext.commands.
Apparently you're looking for a way to store the user input into a variable, here is how you can do :
Using a command
You have defined rr2 as your prefix. Let's assume you are using a cog system :
#commands.command()
async def info(self, ctx, *, input: str):
await ctx.send(input)
return
The await ctx.send(input) line will send a message into the channel where the command has been used that contains what the user had passed as input.
So we have :
>>> rr2 info This is my input.
Output :
'This is my input.'
Using on_message event
If you absolutely want to use an event to store the user input you can use :
#client.event
async def on_message(message):
if message.content.startswith('rr2.info.'):
input = message.content # this will send the message with the 'rr2.info.' prefix
channel = message.channel
await channel.send(input)
This will have the exact same behaviour as the command() solution.
#client.event
async def on_message(message):
if message.content.startswith('rr2.info.'):
# Split method returns a list of strings after breaking the given string by the specified separator
# Example input is 'rr2.info.uwu' then after calling input.split('rr2.info.')
# we will get a list of ['', 'uwu'] , that's why we need to call second index to get the string after
# 'rr2.info.' with [1]
suffix = message.content.split('rr2.info.')[1]
# Don't send it if it's empty, it will be empty if the user for example sent just 'rr2.info.'
if suffix:
await message.channel.send(suffix)
else:
# Overriding the default provided on_message forbids any extra commands from running.
# To fix this, we add client.process_commands(message) line at the end of our on_message
await client.process_commands(message)
I also suggest changing the name client to bot it's nicer.
If you would like to do this same thing with commands you would have to change the source code of commands ext functions, mainly because the space is used as separator between commands/arguments and you want to pass that as a single string.

How do I send the text in a file discord.py

I have made a .txt file in my work file and it doesn't work when I write
this
#client.command()
async def readlist():
await client.say('here you go')
await client.send_file('blacklist.txt')
send_file requires that a destination be passed as the first parameter (such as a text channel object.)
You would need get the channel object within readlist somehow, the easiest way probably being pass_context=True in the command annotation and adding a parameter to readlist for the context object passed. E.g.
#client.command(pass_context=True)
async def readlist(ctx):
# you can now get the channel the command was called in with ctx.message.channel

Resources