Discord.py private messages - python

I am trying to make a discord bot that sends a DM to someone with a command like:
!messagesteve hello world
and it would send a message directly to the person I want.
I've tried the following, but to no avail:
#client.command(pass_context=True)
async def dm(ctx):
user=await client.get_user_info("381870129706958")
await client.send_message(user, "test")
Any help is appreciated.

It seems as though you're using the old docs of d.py (v0.16.x). The most recent version is on rewrite (v1.x).
One of the changes, amongst others, is that context is automatically implied (you don't need pass_context=True) and the syntax for sending messages has changed, as you'll see in the example:
#client.command()
async def dm(ctx, member: discord.Member, *, message):
try:
await member.send(message)
except: # this will error if the user has blocked the bot or has server dms disabled
await ctx.send("Sorry, that user had DMs disabled!")
else:
await ctx.send(f"Successfully sent {member} a DM!")
The usage, assuming a prefix of !, the usage of the command will be:
!dm #Skyonimous Hey there, I'm DMing you from a bot!
* in the arguments "consumes rest", which means that the argument that succeeds it (message) will act as one whole argument, no matter the number of spaces, so you can send a whole paragraph to a user if you want!
If there's anything that you want me to clarify, I'll be more than happy to!
References:
Major changes 0.16.x -> 1.x
Recent docs
Member.send()
Context.send()

Related

Say command that disables #everyone for non-administrators

EDIT: I have fixed the code by just using another method, thanks for the other helpful answers though!
I'm making a say command, it just takes the user's message and repeats it via the bot. But it can be abused to ping everyone etc. So I want to make it so when the User isn't an admin it checks the message for #everyone or #here. Then it says that you can't ping everyone and reacts to the output 'You cant ping everyone' message with a custom command.
It's also in a cog btw. The command, when used, doesn't throw any console errors, instead not doing anything.
EDIT: I have fixed the code by just using another method, thanks for the other helpful answers though!
#commands.command()
async def say(self, ctx, *, message):
await ctx.message.delete()
if not ctx.message.author.guild_permissions.administrator:
if "#everyone" in message or "#here" in message:
antiping = "You can't mention everyone through me!"
await ctx.send(antiping)
await antiping.add_reaction(emoji=':Canteveryone:890319257534103603')
return
else:
await ctx.message.delete()
await ctx.send(message)
You can use allowed_mentions for this. Two ways of using this:
Pass in Bot when initializing:
client = bot(.....,
allowed_mentions = discord.AllowedMentions(everyone = False)
)
You can also pass the same object when sending a message:
ctx.send(...,
allowed_mentions = discord.AllowedMentions(everyone = False)
)
I'd recommend you read the docs for more info on how it works.
You can adjust mentions for the following attributes:
everyone
replied_user
roles
users
A way of doing this would be when you execute your command, it modifies the role "everyone" so that they cant ping the role
Admins bypass ALL restrictions so they would still be able to ping the role besides

discord.py custom help message

I'm making a bot for discord and I want to have a custom help-message. I tried:
from discord.ext import commands
bot = commands.Bot(command_prefix="!")
#bot.command()
async def help(ctx):
member = ctx.author
await ctx.send(member, "test successful")
bot.run('TOKEN')
It's supposed to send a private message to the user and send them whatever. But when I enter !help the bot doesn't even react to the message.
Sending a message only has one positional argument (the message itself) and options. In order to send a DM message, you will need to send on the member class instead.
await member.send("test successful")
When defining your bot, the default is to have an automatic help command. commands.Bot has a keyword parameter help_command that you can set to None to make sure that the automatic help command is turned off. Also, to send a direct message to someone, you have to use user.send(). Your original command also required you to mention the user, as it took a Member as an argument. I'm not sure if that was what you want, but I wouldn't think so.
Here's what I would do:
bot = commands.Bot(command_prefix="!",help_command=None)
#bot.command()
async def help(ctx):
await ctx.author.send("test successful")
Edit: clarity in my explanation.

await client.wait_for isn't working correctly discord.py

possible cause #2 is probably what's happening
Why I am using this:
I am trying to get my bot to detect a bot's embed message (to get the in-game currency of a player) using
await client.wait_for
Problem
However, it somehow does not detect the embeds sent by the bot. It still acknowledges it as long as it has plain text sent together with the embed or it sends the plain text on its own. The
#client.event
async def on_message(message):
code will still work if the bot has sent embeds with or without the text.
Possible causes:
1. ❌Already tested and proven not the cause❌ That my bot cannot read messages from bots
2. Possible: That my bot is slower that the bot I am testing with, so once my bot detects a message sent by a user for the bot to react, the bot has already responded with another message, so the bot is still waiting for a non-existent message. I have not found a viable, not time-consuming way to test this
3. Possible: {this question}
Others
All help will be appreciated! Please also point out any errors in my code here and whether I am using the right code to detect embeds and/or messages by bots. I would also appreciate alternative ways of doing my code.
Code
A portion of my current code is:
def pred(m):
return m.author == client.get_user(490707751832649738)
try:
msg = await client.wait_for('message', check=pred, timeout=10.0)
except asyncio.TimeoutError:
await message.channel.send('Looks like Taco-shack is down :/')
else:
await message.channel.send('You said {0.content}, {0.author}.'.format(msg))
Please ignore the indentations. It was fresh copypasta from my code. I modified it from the API https://discordpy.readthedocs.io/en/latest/migrating.html#waiting-for-events
output:
Looks like taco-shack is down which is the output of an asyncio timeout error
P.S. This is my first question after creating my stack overflow account, I realised that there were already so many articles that I could refer to. So I kept searching, but I could only not find the solution to this question. Please ignore my poor formatting!
Edit:
in response to my comments, I shall make it more clear
I have amended my above code because of Eric's help. He commented something that led me to improve my code ;)
Thanks
In response to Patrick's comment (thanks a lot for directing me to the https://stackoverflow.com/help/minimal-reproducible-examrple help page, really appreciate it ;)), here are a few steps you can go to reproduce the code.
Steps to reproduce the problem
Step 1:
Go to the Discord developer portal and create 2 bots, one for sending the embed and the other for this testing thing (one if you have a random bot that can send embeds
Step 2:
Invite the bot(s) to your server
Step 3:
Code the first bot to send an embed once you sent a message inside any channel maybe a simple embed like the one in How can I send an embed via my Discord bot, w/python? and also maybe an else added to it and that else sends some plain text. Remember to use client.run()!
Step 4
Code the second bot like this:
#client.event
async def on_message(message):
def pred(m):
return m.author == client.get_user(490707751832649738)
try:
msg = await client.wait_for('message', check=pred, timeout=10.0)
except asyncio.TimeoutError:
await message.channel.send('Looks like Taco-shack is down :/')
else:
await message.channel.send('You said {0.content}, {0.author}.'.format(msg))
client.run('token')
Step 5:
Run the two bots!
More questions:
I don't seem to understand whats the use of using message.embeds. I am trying to wait for a message to be sent under the on.message to continue the thread after someone types .balance to see the value of their account so that the bot can get the information. However, it does not recognise a message was sent by the bot
Legality/ethicality
The idea of making this bot came because Carl could not send the message ID.
This part is to see how much money the user has left along with whether the person has successfully sent the donation so that false donations do not clutter the channel
This bot is not meant to be a self bot.
and should not be thought as one.
** If and when you find out that this is not legal, please give a 'no' answer or comment that it is not legal (I prefer the latter) **
I can't reproduce this. Here's what I'm doing
#bot.event
async def on_message(message):
if message.author.id == bot.user.id:
print(message.content)
print(message.embeds)
await bot.process_commands(message)
#bot.command()
async def comm(ctx):
msg = await bot.wait_for('message', check=lambda m: m.author.id == bot.user.id)
await ctx.send(f"{msg.content} {msg.embeds}")
#bot.command()
async def send_content(ctx):
await ctx.send("content1")
#bot.command()
async def send_embed(ctx):
embed = Embed(title="Title1")
await ctx.send(embed=embed)
#bot.command()
async def send_both(ctx):
embed = Embed(title="Title2")
await ctx.send("content2", embed=embed)
I only have the one bot, so maybe that's the problem, but by running !comm and then !send_embed, the bot will detect its own embed-only message from wait_for. One thing I do in this code is to compare objects by id instead of by simple equality.
I edited my on_message to detect the response the second it hears the message. Thanks for all your help :) It was the 2nd thing I ruled out

discord.py - Send messages though console

ok, I wanted so I could send messages in an specific server and channel form the console. I seen on other post how to send messages on specific servers and channels but theyr from the discord app and not console. Can someone help me?
I wanted so I type msg [server-id-here] [channel-name] [message] for example
msg 493121776402825219 general hello
Code I have but it has errors
#bot.event
async def on_ready(ch, *, msg):
while msg:
channel = bot.get_channel(ch)
msg=input("Mensagem: ")
if channel:
await bot.send_message(channel, msg)
else:
await bot.say("I can't find that channel")
Error that outputs
TypeError: on_message() missing 1 required positional argument: 'ch'
I don't this this is actually possible, however you can implement a new command to do it, heres the one I used for welcomer
#bot.command(description="Echos, developers only", pass_context=True)
async def echo(ctx, echowords:str):
if ctx.message.author.id in []: #put in id's in a list or replace it with one string
await bot.say(echowords)
else:
await bot.say("Bot developers only :<")
This makes the bot repeat what you said where you said it, but if you want to send messages to a specific channel by ID you can do this
#bot.command(description="Echos, developers only", pass_context=True)
async def echo(ctx, id, echowords:str):
if ctx.message.author.id in []: #put in id's in a list or replace it with one string
sendchannel = bot.get_channel(id)
await bot.send_message(sendchannel, echowords)
else:
await bot.say("Bot developers only :<")
Use the say command.
#bot.command()
async def say(ctx, *,message):
if not ctx.author.bot:
else:
pass

How to make a discord.py bot private/direct message someone who's not the author?

Say I want to make a bot with a "poke" feature (aka sends a pm to a user saying "Boop" when someone says "!poke #user#0000"), how would I do this? It works perfectly when I do this:
#bot.command(pass_context=True)
async def poke(ctx, message):
await client.send_message(ctx.message.author, 'boop')
but only if I want to poke the author of the message. I want to poke whoever's being #'d.
I know the discord.py documents say I can use this:
start_private_message(user)
but I don't know what to put in place of user.
It's actually simpler than that
#bot.command(pass_context=True)
async def poke(ctx, member: discord.Member):
await bot.send_message(member, 'boop')
send_message contains logic for private messages, so you don't have to use start_private_message yourself. The : discord.Member is called a converter, and is described in the documentation here
I might be necroing this post a bit, but the recent version of this would look like this:
#bot.command():
async def poke(ctx, user: discord.Member=None):
if user is None:
await ctx.send("Incorrect Syntax:\nUsage: `!poke [user]`")
await user.send("boop")
The if user is None: block is optional, but is useful if you want to have an error message if a command isn't used correctly.

Categories

Resources