This is a bit of a general question for Discord.py, but how would I check if a role or an emoji has just been created or uploaded in the server? I am using the discord and discord.ext modules and I have the commands.Bot. My code is really long, which is why I will not include it here, and this is a general question anyways, but one of my bot's features is a modlog system. I already have the database and commands set up, but I want an extra feature where my bot can send a message if a new role was just created. Is there any bot.event handler that allows me to do this, like on_role_created or something similar to that?
You may be looking for on_guild_role_create and on_guild_emojis_update.
Here's two quick examples of how you can use them:
#bot.event
async def on_guild_role_create(role):
print(f'Server: {role.guild.name}\nRole: {role.name}'
#bot.event
async def on_guild_emojis_update(before, after):
before = ', '.join([emoji.name for emoji in before])
after = ', '.join([emoji.name for emoji in after])
print(f'Emoji list updated :\nBefore : {before}\nAfter : {after}')
Related
So I'm creating a bot that can change the perms of roles. and to start I wanted to code a thing that allows me see and check what role has been mentioned. I want the identification to be open to all roles not just one because later on I want to be able to change the perms of multiple roles at once.
#client.event
async def on_message(message):
if message == client.user:
return
if message.channel.name in ['general']:
if message.content.lower().startswith('!rc'):
role = str(message.role.id)
await message.channel.send (f'{message.role.mention}')
return
So far I have tried doing this where I create a .startswith for the initial command then I create a "role" variable that I then use to mention that role but this doesn't work, can someone help/point me in the right direction in getting this?
Don't use on_message event for these type of commands because you would need to put a bunch of code to solve this problem with that event. Use the below code which helps to solve your problem in an easy manner
#client.command()
async def role(ctx,role:discord.Role):
if ctx.channel.name=="general":
await ctx.send(role.mention)
I make a Discord bot and I want to create a feature when bot reacts depending on the command content
For example:
if message.content.startswith("!send <:grin:>"):
await message.channel.send("π")
if message.content.startswith("!send <:angry:>"):
await message.channel.send("π ")
Making command for every emoji is useless (There are over 3600+ emojis). Any ideas?
The best thing to do is to either:
a- Use a dictionary for each emoji you want to add
emojiDict = {":grin:":π,":angry:":π }
if message.content.startswith("!send <"):
emoji = message.content[-7:-1]
await message.channel.send(emojiDict[emoji])
b- Post whatever the user does after the !send
if message.content.startswith("!send <"):
emoji = message.content[-7:-1]
await message.channel.send(emoji)
The advantage of method 2 is that you don't need to hardcode each and every emoji, but then the user can also post anything after !send and it will send, even if it is not an emoji.
You can add additional checks to make sure its an emoji (make sure it starts and ends with a ":" as well.
You can simply use the commands arguments, like this:
#Bot.command()
async def send(ctx, emoji_name):
await ctx.send(f":{emoji_name}:")
Hey i am trying to get all the users in a specific guide, and i am getting part of the users and not all of them, why?, And i dont care about discord terms, i am not gonna spam servers or something like this so please help instead telling me the discord rules because i am know it well, This is the code i did,
import discord
import asyncio
intents = discord.Intents(messages=True, guilds=True, members=True)
client = discord.Client(intents=intents)
token = ""
#client.event
async def on_ready():
print("Bot Is Ready!")
guild = client.get_guild(328154277111398403)
for member in guild.members:
print(member)
await asyncio.sleep(0.1)
client.run(token, bot=False)
in the context of selfbots/userbots, discord.py doesn't actually have the ability to get the member list (or, at least, a significant portion of it), and therefore is not suited for this task. Instead, you'll either have to use a different library or code your own solution. Keep on reading for some code :)
Code:
A python lib with this support is discum.
Here's the least amount of code required to get the member list with discum:
import discum
bot = discum.Client(token='blah blah blah')
#bot.gateway.command
def helloworld(resp):
if resp.event.ready_supplemental:
bot.gateway.fetchMembers("GUILD_ID_HERE", "CHANNEL_ID_HERE")
bot.gateway.run()
And here's another example that creates a function called get_members that returns the member list: https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/examples/gettingGuildMembers.py
And here are more examples:
https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/docs/fetchingGuildMembers.md
How does it work?
Since we can't request for the member list the same way bot accounts can, we instead need to exploit the member list (yea, that members sidebar on the right that you see when going to a guild). We need to read that entire thing, piece by piece.
Essentially how it's done is the client first subscribes to member events in a channel in a guild (Luna somewhat went over this in her unofficial discord docs, but left out a lot). Then, as the user scrolls through the member list, more lazy requests are sent to get each chunk of the member list. And this is what happens in discum: lazy requests are sent until the entire member list is fetched. Here's some more info.
I've been trying to develop a discord bot in python recently. I made it so that if a message contains a certain number, it will react and send a message. Here is the code in the cog file:
import discord
from discord.ext import commands
nice_numbers = ['69', '420']
class Auto(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_message(self, message):
msg = message.content
if message.author == self.client.user:
return
if any (word in msg for word in nice_numbers):
await message.add_reaction('π')
await message.channel.send(f'lmao nice')
def setup(client):
client.add_cog(Auto(client))
The problem is, the bot also responds with the same message and reaction when a user mentions a certain channel (in this case #general, #super-private-testing, and #resources). I can't seem to fix it or figure out why it's happening. I'm still pretty new to python so can someone please tell me what I'm doing wrong?
Basically what is happening is that mentions have a special syntax within the Discord API where they are basically a bunch of numbers put together.
For example when you are mentioning another user like the following:
Hello #User1234!
The real syntax within the discord message is the following:
Hello <#125342019199458000>!
And in the case of mentioning channels, it works similar, as a channel mentioned like:
#general
Internally would be written as:
<#550012071928922144>
Of course, the problem is that within this big number there could be false positive of finding your nice_numbers. There could be different ways to avoid this, for example you could check if a channel or a user is being mentioned in the message and return in that case.
if message.channel_mentions or message.mentions:
return
I think a better solution would be to changing the way you are checking if the nice_numbers are within message.content.
Using if word in msg would return true if message.content also includes something like 'My favourite number is 45669'. To overcome this issue it is better to make use of regular expressions.
You can declare a new function like this answers explains, which would return a <match object> if what you pass as parameter is found.
It would be something like this:
import re
def findCoincidences(w):
return re.compile(r'\b({0})\b'.format(w)).search
findCoincidences('69')('I like 69') # -> return <match object>
findCoincidences('69')('My favourite number is 45669') # -> return None
Expanding on Shunya's answer, you can use message.clean_content instead of message.content:
A property that returns the content in a βcleaned upβ manner. This basically means that mentions are transformed into the way the client shows it. e.g. <#id> will transform into #name.
This will also transform #everyone and #here mentions into non-mentions.
This will prevent you from inadvertently matching against the IDs of channels, users, roles, etc. Of course, if the actual name contains a nice_number, it'll still match.
I've been trying to create a discord bot with Python. One of the commands was suppose to remove of the user's roles and add a specific one. And then if they were on a voice channel send them to another specific voice channel. I tried the following code:
#client.command()
async def prisioner(member:discord.member):
role=await guild.get_role(702269742014005248)
channel=await guild.get_channel(690488036781195294)
await client.add_roles(member, role)
if member.activity!=None:
await move_to(channel)
It's not working and doesn't show any errors on the IDLE. Can someone help?
A couple of things to mention:
When using command decorators, Context is always the first argument (see references).
Be careful with your spelling, as I'm guessing the command was supposed to be called prisoner, and if that's the case, then you made a typo; prisioner.
It seems that some of the code's syntax is based off of the old discord.py version, so when using documentation, stick to the most recent one (see references).
You seem to be awaiting a few things unnecessarily. The await keyword should only be used for coroutines (it'll tell you in the docs).
You're setting parameter types really well - definitely a good habit to get into from the get-go.
And before we move onto your command, please make sure you have await client.process_commands(message) if you're using an on_message(message) event.
Your command, rewritten:
#client.command()
async def prisoner(ctx, member: discord.Member):
role = ctx.guild.get_role(702269742014005248)
v_channel = ctx.guild.get_channel(690488036781195294) # assuming this is a voice channel?
await member.add_roles(role)
if member.voice.channel: # checks user is connected to a voice channel
await member.move_to(v_channel)
await ctx.send(f"Successfully imprisoned {member.mention}!")
References:
Member.move_to()
Guild.get_role()
Guild.get_channel()
VoiceState.channel
commands.Context
discord.on_message
Bot.process_commands()