welcome/goodbye using discord.py - python

I'm trying to create a bot that greets a user that joins a server. But make it so that the person is greeted in the server itself rather than as a DM (which most tutorials I've found teach you how to do).
This is what I've come up with so far.
#bot.event
async def on_member_join(member):
channel = bot.get_channel("channel id")
await bot.send_message(channel,"welcome")
but, it doesn't work and instead throws up this error.
Ignoring exception in on_member_join
Traceback (most recent call last):
File "C:\Users\Lenovo\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\Lenovo\Documents\first bot\bot.py", line 26, in
on_member_join
await bot.send_message(channel,"welcome")
File "C:\Users\Lenovo\AppData\Local\Programs\Python\Python36\lib\site-
packages\discord\client.py", line 1145, in send_message
channel_id, guild_id = yield from self._resolve_destination(destination)
File "C:\Users\Lenovo\AppData\Local\Programs\Python\Python36\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

You aren't passing the correct id to get_channel, so it's returning None. A quick way to get it would be to call the command
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.command(pass_context=True)
async def get_id(ctx):
await bot.say("Channel id: {}".format(ctx.message.channel.id))
bot.run("TOKEN")
You could also modify your command to always post in a channel with a particular name on the server that the Member joined
from discord.utils import get
#bot.event
async def on_member_join(member):
channel = get(member.server.channels, name="general")
await bot.send_message(channel,"welcome")

The answer by Patrick Haugh is probably your best bet, but here are a few things to keep in mind.
The Member object contains the guild (server), and the text channels the server contains.
By using member.guild.text_channels you can ensure the channel will exist, even if the server does not have a 'general' chat.
#bot.event
async def on_member_join(member):
channel = member.guild.text_channels[0]
await channel.send('Welcome!')

Try this:
#bot.event
async def on_member_join(member):
channel = discord.utils.get(member.guild.channels, name='the name of the channel')
await channel.send(f'Enjoy your stay {member.mention}!')

Related

Discord bot on_join_guild dm everyone

I am trying to dm everyone in the server when the bot is added to the server using the on_join_guild().
The code for it
#client.event
async def on_guild_join(guild):
for member in guild.members:
await member.create_dm()
embedVar = discord.Embed(title="Hi", description="Hello", color=0x00ff00)
await member.dm_channel.send(embed=embedVar)
But whenever I add the bot to server, it dms everyone in the server which is expected but a error also pops in the console.
Ignoring exception in on_guild_join
Traceback (most recent call last):
File "C:\Users\Khusi\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File ".\time-turner.py", line 42, in on_guild_join
await member.create_dm()
File "C:\Users\Khusi\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\member.py", line 110, in general
return getattr(self._user, x)(*args, **kwargs)
AttributeError: 'ClientUser' object has no attribute 'create_dm'
What am I doing wrong?
After replicating your code, I found that your error only appears to happen if the bot tries to message itself. You would also get an error if your bot attempts to message another bot (Cannot send messages to this user). You can just use pass if your bot can't message a user or if it tries to message itself.
#client.event
async def on_guild_join(ctx):
for member in ctx.guild.members:
try:
await member.create_dm()
embedVar = discord.Embed(title="Hi", description="Hello", color=0x00ff00)
await member.dm_channel.send(embed=embedVar)
except:
pass
If the above still doesn't work, just as NerdGuyAhmad had said, you need to enable intents, at the very least member intents. View this link here: How do I get intents to work?

How to get your Discord bot to say something specific, then delete the previous message

Im new to working with discord.py, basically im simply trying to make my discord bot say something then delete the previous text, so for example I want to type "/say hello" then I want the bot to grab that, remove the prefix and just print "hello", Ive already googled and searched and found another guide but there was no follow up answers and when I tried the solutions they errored, below is the code im using
import discord
from discord.ext import commands
bot = discord.Client()
prefix = "/"
#bot.event
async def on_ready():
print("Online")
#bot.event
async def on_message(message):
args = message.content.split(" ")[1:]
if message.content.startswith(prefix + "say"):
await bot.delete_message(message)
await bot.send_message(message.channel, " ".join(args))
bot.run("token")
and this is the error the console prints out
C:\Users\unknownuser\anaconda3\envs\discordbot\pythonw.exe C:/Users/unknownuser/PycharmProjects/discordbot/bot.py
Online
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\unknownuser\anaconda3\envs\discordbot\lib\site-packages\discord\client.py", line 313, in _run_event
await coro(*args, **kwargs)
File "C:/Users/unknownuser/PycharmProjects/discordbot/bot.py", line 15, in on_message
await bot.delete_message(message)
AttributeError: 'Client' object has no attribute 'delete_message'
As I start learning the documentation and logic behind it I should start figuring it out for myself but this one has me stumped, Help would be appreciated
Looks like you're using a tutorial for an old version of discord.py.
There are some major changes in the most recent - rewrite - version.
Example for your code
# using the command decorator
#bot.command()
async def say(ctx, *, sentence):
await ctx.message.delete()
await ctx.send(sentence)
#############################################
# using the on_message event
#bot.event
async def on_message(message):
args = message.content.split(" ")[1:]
if message.content.startswith(prefix + "say"):
await message.delete()
await message.channel.send(" ".join(args))
else:
await bot.process_commands(message) # allows decorated commands to work
References:
Message.delete()
Bot.process_commands()
Messageable.send()

How to send an embed on client ready

I am creating a bot with discord.py.
I would like to send an embed to a specific discord channel when the bot is ready. To do that, here is my code:
import discord
client = discord.Client()
logchannel = client.fetch_channel(692934456612487199)
#client.event
async def on_ready():
print(f'Ticket Tool active as {client.user}')
embed = discord.Embed(title="**Jokz' Ticket Tool**", color=0xff0000, description="Started Successfully!")
embed.set_footer(text="JokzTickets | #jokztools",icon_url="https://pbs.twimg.com/profile_images/1243255945913872384/jOxyDffX_400x400.jpg")
embed.set_thumbnail(url="https://gifimage.net/wp-content/uploads/2017/10/check-mark-animated-gif-12.gif")
await logchannel.send(embed=embed)
client.run(key)
When I run this, I get the following error:
PS C:\Users\jokzc\Desktop\jokzticketspy> py index.py
Ticket Tool active as Jokz' Tools#5577
Ignoring exception in on_ready
Traceback (most recent call last):
File "C:\Users\jokzc\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\client.py", line 312, in _run_event
await coro(*args, **kwargs)
File "index.py", line 15, in on_ready
await logchannel.send(embed=embed)
TypeError: send() takes no keyword arguments
What would the correct way to format this be?
So I ended up figuring out that it worked if I changed the function from client.fetch_channel to client.get_channel and I needed to put this in the actual on_ready function! The reason for this is because the client cannot get or fetch the channel until the client is actually ready.
The corrected code looks like this:
#client.event
async def on_ready():
logchannel = client.get_channel(692934456612487199)
print(f'Ticket Tool active as {client.user}')
embed = discord.Embed(title="**Jokz' Ticket Tool**", color=0x00ff00, description="Started Successfully!")
embed.set_footer(text="JokzTickets | #jokztools",icon_url="https://pbs.twimg.com/profile_images/1243255945913872384/jOxyDffX_400x400.jpg")
embed.set_thumbnail(url="https://gifimage.net/wp-content/uploads/2017/10/check-mark-animated-gif-12.gif")
await logchannel.send(embed=embed)
#client.event
async def on_ready():
channelid = client.get_channel(id)
botname = client.user.name
print('message ' + botname)
embed = discord.Embed(title=f"Text", description="Text", color=discord.Color.red())
embed.set_footer(text="Your text", icon_url="URL of icon")
embed.set_thumbnail(url="Url")
await channelid.send(embed=embed)

Discord.py Module Python 3.6.4 kick feature

I was making a discord bot using the discord module in python... I am having a lot of trouble trying to make the kick command work. I tried using bot.kick, client.kick and ctx.kick but they all give the same error which says,
Ignoring exception in command kick:
Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\core.py", line 62, in wrapped
ret = yield from coro(*args, **kwargs)
File "C:\Users\user\Desktop\Code\bot.py", line 44, in kick
await client.kick(user)
AttributeError: 'Client' object has no attribute 'kick'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\bot.py", line 886, in invoke
yield from ctx.command.invoke(ctx)
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\core.py", line 493, in invoke
yield from injected(*ctx.args, **ctx.kwargs)
File "C:\Users\user\AppData\Roaming\Python\Python36\site-packages\discord\ext\commands\core.py", line 71, in wrapped
raise CommandInvokeError(e) from e
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Client' object has no attribute 'kick'
I tried searching various different youtube videos and posts related to the problem I am having but nobody seems to be having a solution. I have written the code below. If you spot any errors which I missed please let me know.
import time
import random
import discord
import asyncio
from discord.ext import commands
#Initialize
client = discord.Client()#Creates Client
bot = commands.Bot(command_prefix='!')#Sets prefix for commands(!Command)
#bot.event
async def on_ready():
print('Name:', end=' ')
print(bot.user.name)
print('ID: ')
print(bot.user.id)
#bot.command(pass_context=True)
async def user_info(ctx, user: discord.Member):
await ctx.send(f'The username of the user is {user.name}')
await ctx.send(f'The ID of the user is {user.id}')
await ctx.send(f'The status of the user is {user.status}')
await ctx.send(f'The role of the user is {user.top_role}')
await ctx.send(f'The user joined at {user.joined_at}')
#bot.command(pass_context=True)
async def kick(ctx, user: discord.Member):
await ctx.send(f'The Kicking Hammer Has Awoken! {user.name} Has Been Banished')
await client.kick(user)
bot.run('SECRET')
client.run('SECRET')
You appear to be using the newer discord.py 1.0, also called the rewrite branch. You should read this, which is the documentation of the many breaking changes that were made in that switch. You should also refer solely to that documentation, as most documentation for the older 0.16 version is not compatible.
Many things were moved out of Client and into places that made a little more sense. Specifically, kick is now a method of Guilds.
import asyncio
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.event
async def on_ready():
print('Name:', end=' ')
print(bot.user.name)
print('ID: ')
print(bot.user.id)
#bot.command(pass_context=True)
async def user_info(ctx, user: discord.Member):
await ctx.send(f'The username of the user is {user.name}')
await ctx.send(f'The ID of the user is {user.id}')
await ctx.send(f'The status of the user is {user.status}')
await ctx.send(f'The role of the user is {user.top_role}')
await ctx.send(f'The user joined at {user.joined_at}')
#bot.command(pass_context=True)
async def kick(ctx, user: discord.Member):
await ctx.send(f'The Kicking Hammer Has Awoken! {user.name} Has Been Banished')
await ctx.guild.kick(user)
bot.run('secret')
Note that I've also removed all references to client in the above. Bot is a subclass of Client, so you can access all the Client methods through Bot.

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