Getting a discord bot to mention other users - python

I am working on a bot to do some simple commands for my discord server and I haven't been able to figure out how to get the bot to mention people who aren't the author.
if message.content.startswith("+prank"):
user = client.get_user_info(id)
await client.send_message(message.channel, user.mention + 'mention')
When I try to run the command i come up with the error message:
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\discord\client.py", line 307, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "C:/Users/user/Desktop/Murk-Bot 2.0.py", line 130, in on_message
await client.send_message(message.channel, user.mention + 'mention')
AttributeError: 'generator' object has no attribute 'mention'
This happens if I use the command with a mention before, after, and not at all. If it gives some more context here are the imports I am using
import discord
from discord.ext.commands import Bot
from discord.ext import commands
import asyncio
import time
import random

The specific error you are getting is caused by not awaiting a coroutine. client.get_user_info is a coroutine and must use await.
If you want "+prank" to work by mentioning by username, you can find a member object by using server.get_member_named.
Example code provided below. This will check the server the command was called from for the specified username and return the member object.
if message.content.startswith("+prank"):
username = message.content[7:]
member_object = message.server.get_member_named(username)
await client.send_message(message.channel, member_object.mention + 'mention')

It looks like you're trying to implement commands without actually using commands. Don't put everything in the on_message event. If you're not sure how to use the discord.ext.commands module, you can look at the documentation for the experimental rewrite branch.
import discord
from discord.ext.commands import Bot
bot = Bot(command_prefix='+')
#bot.command()
async def prank(target: discord.Member):
await bot.say(target.mention + ' mention')
bot.run('token')
You would use this command with +prank Johnny. The bot would then respond in the same channel #Johnny mention

Related

AttributeError: 'Member' object has no attribute 'avatar_url'

I am trying to make a Discord bot and one of the features is a welcoming from my bot using on_member_join. This is the event:
#bot.event
async def on_member_join(member, self):
embed = discord.Embed(colour=discord.Colour(0x95efcc), description=f"Welcome to Rebellions server! You are the{len(list(member.guild.members))}th member!")
embed.set_thumbnail(url=f"{member.avatar_url}")
embed.set_author(name=f"{member.name}", icon_url=f"{member.avatar_url}")
embed.set_footer(text=f"{member.guild}", icon_url=f"{member.guild.icon_url}")
embed.timestamp = datetime.datetime.utcnow()
await welcome_channel.send(embed=embed)
Although when the bot is working and running and someone joins my server I get this error:
[2022-11-07 19:38:10] [ERROR ] discord.client: Ignoring exception in on_member_join
Traceback (most recent call last):
File "C:\Users\stene\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\client.py", line 409, in _run_event
await coro(*args, **kwargs)
File "C:\Users\stene\OneDrive\Documents\GitHub\bot\main.py", line 25, in on_member_join
embed.set_thumbnail(url=f"{member.avatar_url}")
^^^^^^^^^^^^^^^^^
AttributeError: 'Member' object has no attribute 'avatar_url'
I am running the latest version of discord.py and python.
Thanks!
welcome cog:
import discord
from discord.ext import commands
import asyncio
import datetime
class WelcomeCog(commands.Cog, name="Welcome"):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_member_join(self, member):
embed = discord.Embed(colour=discord.Colour(0x95efcc), description=f"Welcome to Rebellions server! You are the{len(list(member.guild.members))}th member!")
embed.set_thumbnail(url=member.avatar.url)
embed.set_author(name=member.name, icon_url=member.avatar.url)
embed.set_footer(text=member.guild)
embed.timestamp = datetime.datetime.utcnow()
channel = self.bot.get_channel(1038893507961692290)
await channel.send(embed=embed)
async def setup(bot):
await bot.add_cog(WelcomeCog(bot))
print("Welcome cog has been loaded successfully!")
In discord.py 2.0 the attribute Member.avatar_url got removed and replaced by Member.avatar. To access the URL, you should use member.avatar.url.
Check out the migration guide for similar instances. Using pip freeze you can check which version of discord.py you have installed, but I assume it's 2.x, and probably you followed a tutorial or copied a code example that used discord.py 1.x.
Following your code you have several errors, which can be corrected in the following code:
First: async def on_member_join(member, self): is an incorrect code.
self always comes before any other argument if this event is in a cog file, but still it isn't a required argument so completely remove it. The correct code for this line is async def on_member_join(member):
Second: Make sure you're using the correct event listener.
#client.event or #bot.event if this is in your Main file, and #commands.Cog.listener() if this is in your cog file.
Third: Please change (member, self): to (member:discord.Member)
Good luck! :D

Trying to send a message to a specific channel from a different file , discord.py

i splitted some code into another file and i get "'NoneType' object has no attribute 'send'"
as i read , its should be a error like "the channel dont exist" "the bot dont have permission"
but tahts wrong , i can send messages just fine from the main.py in the specific channel just not from the loging.py . here my code .
#bot.py
import discord
import asyncio
from discord.ext import commands
import os
from dotenv import load_dotenv
from datetime import datetime, timedelta, date, time, timezone
import time
import loging
load_dotenv()
TOKEN = os.getenv("DISCORD_TOKEN")
bot = commands.Bot(command_prefix=commands.when_mentioned_or("$"), help_command=None)
#bot.command(name='test', help='this command will test')
async def test(ctx):
await loging.comlog(ctx)
bot.run(TOKEN)
#loging.py
import discord
import asyncio
from discord.ext import commands
import os
from datetime import datetime, timedelta, date, time, timezone
import time
bot = commands.Bot(command_prefix=commands.when_mentioned_or("$"), help_command=None)
timestamp = datetime.now()
timenow = str(timestamp.strftime(r"%x, %X"))
async def comlog(ctx):
channel = ctx.channel
channelid = ctx.channel.id
username = ctx.author
usernameid = ctx.author.id
logingchan = await bot.fetch_channel(983811124929630239)
em = discord.Embed(title=f'${ctx.command}', description=f'{timenow}', color=0x00FF00)
em.set_thumbnail(url=username.avatar_url)
em.add_field(name="Channel:", value=f'{ctx.channel.mention} \n{channelid}', inline=True)
em.add_field(name="User:", value=f'{username}\n{usernameid}', inline=True)
print(f'{timenow}: $help: in "{channel}" by "{username}"')
await logingchan.send(embed=em)
await ctx.message.delete()
for testing i replaced the cahnnel with "ctx" and this works just fine
Ignoring exception in command test:
Traceback (most recent call last):
File "C:\Users\Asuka\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
ret = await coro(*args, **kwargs)
File "C:\Users\Asuka\Desktop\PROJECT\Discord_Bot\bot.py", line 149, in test
await loging.comlog(ctx)
File "C:\Users\Asuka\Desktop\PROJECT\Discord_Bot\loging.py", line 23, in comlog
await logingchan.send(embed=em)
AttributeError: 'NoneType' object has no attribute 'send'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\Asuka\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\ext\commands\bot.py", line 939, in invoke
await ctx.command.invoke(ctx)
File "C:\Users\Asuka\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\ext\commands\core.py", line 863, in invoke
await injected(*ctx.args, **ctx.kwargs)
File "C:\Users\Asuka\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\ext\commands\core.py", line 94, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'send'
yea i know ppl say now , the cahnnel dont exist , the bot dont have premmision . false , why can i send in the exact same channel with my main.py but not with the loging.py . also , if i dont send in a specific channel , and send the embed in channel where the command got used , and i use the channel with the id , my bot can reply in the exact same channel.
You have two separate bots in your two modules.
In the bot.py, you make a bot that you later run with the run method. This bot is fine, and it's connected to discord and can do a bunch of things.
However, you made a second bot in logging.py. This bot isn't actually doing anything and it was never started, so any attempts to get or fetch anything from discord will fail. What you need to do is to give the bot instance to the other module.
You can do this by either putting it into a class, or passing the bot as an argument, which I will show here:
async def comlog(bot, ctx):
channel = ctx.channel
channelid = ctx.channel.id
username = ctx.author
usernameid = ctx.author.id
logingchan = await bot.fetch_channel(983811124929630239)
em = discord.Embed(title=f'${ctx.command}', description=f'{timenow}', color=0x00FF00)
em.set_thumbnail(url=username.avatar_url)
em.add_field(name="Channel:", value=f'{ctx.channel.mention} \n{channelid}', inline=True)
em.add_field(name="User:", value=f'{username}\n{usernameid}', inline=True)
print(f'{timenow}: $help: in "{channel}" by "{username}"')
await logingchan.send(embed=em)
await ctx.message.delete()
# Then pass in the bot when you call the function
#bot.command(name='test', help='this command will test')
async def test(ctx):
await loging.comlog(bot, ctx)
Then you can just delete your second bot definition in logging.py.
If you want permission failure messages you need to use try/except:
try:
await logingchan.send(embed=em)
except discord.errors.Forbidden:
# don't have permissions, do something here
There isn't a bot variable in loging.py
If you want to split bot commands you should make cogs instead
Cogs are like command groups
This is how you do it:
# main.py
from discord.ext import commands
from loging import my_commands_cog
bot = commands.Bot(command_prefix = "idk!")
bot.add_cog(my_commands_cog)
# loging.py
from discord.ext import commands
class my_commands_cog(commands.Cog)
#commands.command(name = "idk")
async def idk(ctx, * , arg):
# stuff
print("idk")
Check it out here: Cogs

Discord if statement with message author role

I know that I must not be the first one trying to do this. But I really cannot find the solution to my problem. Here is what i'm trying to do. I'm trying to print the member role in the channel only if is role is "member". The thing is, i'm not able to get is role and use it in the IF statement. I tried a lot of thing until I finally understood that the object Client doesn't have a get_context method. But everyone is using it and seems to be able to make things work. I've read the official API docs and I can clearly see that the object "Client" doesn't have a get_context method, but the ext.command.Bot object does. What can I do to make things work ?.
Here is the error I get:
Ignoring exception in on_message
Traceback (most recent call last):
File "/home/runner/Discord-Moderator/venv/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "main.py", line 21, in on_message
ctx = await client.get_context(message)
AttributeError: 'Client' object has no attribute 'get_context'
Here is my code:
import discord
import os
import random
from stayin_alive import stayin_alive
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
msg = message.content.lower()
ctx = await client.get_context(message)
if message.author == client.user:
return
role = discord.utils.find(lambda r: r.name == 'Member', ctx.message.server.roles)
if role in message.author.roles:
await message.channel.send("You are a member")
I even tried with the commands thing in order to do it like this Discord.py bot.get_context() does not return ctx object
import commands
from stayin_alive import stayin_alive
client = discord.Client()
bot = commands.Bot(command_prefix=("!sm"))
But I get this error:
Traceback (most recent call last):
File "main.py", line 4, in <module>
import commands
ModuleNotFoundError: No module named 'commands'
Here is everything I checked out:
https://www.codegrepper.com/code-examples/python/discord.py+add+role+to+user
https://discordpy.readthedocs.io/en/stable/ext/commands/api.html (Bot command Object official Doc)
https://discordpy.readthedocs.io/en/stable/api.html (Client Object Official Doc)
Discord.py bot.get_context() does not return ctx object
https://www.reddit.com/r/learnpython/comments/o8jpi6/so_im_making_a_discord_bot/
How can I get a Discord Context Object from the on_message event?
Can someone please help me to find the solution to my problem. I simply wanna use the message.author.role in my IF statement.
Here is the solution, I've finally found it, I wasn't that far, I knew I could do it without using ctx

Create Server using Discord Bot

If we look at the Guild Create event in the discord dev documentation, we see the following:
I have a couple of questions about this. First of all, I am not sure exactly when I can create a server using a bot account. Following the "when a user is initially connecting" section, I attempted to place the server creation into the on_ready function, like so:
import discord
import asyncio
import bot.client.getkey as _getkey
from bot.utils import get_owner
class ImABot(discord.Client):
async def on_ready(self):
ts = await self.create_server("test")
inv = await self.create_invite(ts.default_channel)
await self.send_message(get_owner()) #get owner simply gets the user who owns the bot, me.
Bot = ImABot()
Bot.run(_getkey.key())
However, I get the following error:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/discord/client.py", line 307, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "/Users/edl/Desktop/ /Programming/Github/Democracy-Bot/demobot/client/client.py", line 22, in on_ready
inv = await self.create_invite(ts.default_channel)
File "/usr/local/lib/python3.6/site-packages/discord/client.py", line 2628, in create_invite
data = yield from self.http.create_invite(destination.id, **options)
AttributeError: 'NoneType' object has no attribute 'id'
I assume this means the server was not created. I hope someone can give me information on when creating a server will work, and whether or not it is possible in the first place. Thanks!
Guilds no longer have default channels, so it is best to avoid using them.
To get the first created channel for the server, your best bet is to use
discord.utils.get(new_server.channels, type=discord.ChannelType.text)
Or if you use discord.py rewrite, then
new_server.text_channels[0]
Then you can create the invite from that channel.

How to use discord.py event handler on_voice_state_update to run only when a user joins a voice channel

I am trying to learn how to make a discord bot through discord.py and wanted to add a feature where a message would be sent from the bot whenever another user joined the voice channel that the bot is currently in. I do not know how to use the event handler itself and didn't understand their documentation enough to utilize it.
from discord.ext.commands import Bot
client = Bot(command_prefix="!")
#client.event
async def on_voice_state_update(before, after):
await client.say("Howdy")
From my limited understanding of the documentation, the event handler should be used whenever a user is muted, deafened, leaves, or joins a channel.
However, even when I tried to get it to recognize those actions it gave me an error message of:
Ignoring exception in on_voice_state_update
Traceback (most recent call last):
File "C:\Users\Sam\PycharmProjects\FunBotProject\venv\lib\site-packages\discord\client.py", line 307, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "C:/Users/Sam/PycharmProjects/FunBotProject/my_bot2.py", line 63, in on_voice_state_update
await client.say("Xd ")
File "C:\Users\Sam\PycharmProjects\FunBotProject\venv\lib\site-packages\discord\ext\commands\bot.py", line 309, in _augmented_msg
msg = yield from coro
File "C:\Users\Sam\PycharmProjects\FunBotProject\venv\lib\site-packages\discord\client.py", line 1145, in send_message
channel_id, guild_id = yield from self._resolve_destination(destination)
File "C:\Users\Sam\PycharmProjects\FunBotProject\venv\lib\site-packages\discord\client.py", line 289, in _resolve_destination
raise InvalidArgument(fmt.format(destination))
discord.errors.InvalidArgument: Destination must be Channel, PrivateChannel, User, or Object. Received NoneType
A version working in 2020.
Please not that my code behaves different in terms of the sent message.
from discord.ext.commands import Bot
bot = commands.Bot(command_prefix='!')
#bot.event
async def on_voice_state_update(member, before, after):
if before.channel is None and after.channel is not None:
if after.channel.id == [YOUR_CHANNEL_ID]:
await member.guild.system_channel.send("Alarm!")
client.say can only be used inside of commands, not events. See documentation here.
Can I use bot.say in other places aside from commands?
No. They only work inside commands due to the way the magic involved works.
The makes sense since a command will always be called from a text channel, meaning that the response from the bot can be sent to the same channel.
In your case, when a user joins a voice channel, the bot does not know to which text channel to send "Howdy".
To fix this, use client.send_message instead of client.say. In the example code below, "Howdy" will be sent to the "general" text channel every time the on_voice_state_update event is triggered.
from discord.ext.commands import Bot
client = Bot(command_prefix="!")
#client.event
async def on_voice_state_update(before, after):
if before.voice.voice_channel is None and after.voice.voice_channel is not None:
for channel in before.server.channels:
if channel.name == 'general':
await client.send_message(channel, "Howdy")

Categories