So I am using discord.py to make a discord Client. I am using on_voice_state_update to see if the VoiceState of a member changes.
If a member is inside a specific VoiceChannel, I want the client to create a new voice channel, using the member's username as the name of the channel, and move the member inside that new voice channel. Here is my code:
import discord, asyncio
app = discord.Client()
#app.event
async def on_voice_state_update(user_name, user_id, after):
name2 = str(user_name)
ch = app.get_channel(660213767820410918)
guild = app.get_guild(660213767820410893)
member = str(user_id)
if after.channel == ch:
await guild.create_voice_channel(name=(name2+'`s Room'), category=guild.get_channel(660213767820410908) ,user_limit=99 ,overwrites=(user_name ,{'manage_channels': True}))
await guild.member.move_to(channel, reason=None)
This doesn't work. Could anyone please help me?
There were a couple of errors.
First of all, the event on_voice_state_update accepts three parameters, which are member, before and after instead of user_name, user_id and after.
When you used the guild.create_voice_channel function, you did not pass a proper dictionary and you forgot to assign channel to the newly created channel (that is why channel was undefined).
Finally, you should have used member.move_to instead of guild.member.move_to as guild.member is undefined.
import discord, asyncio
app = discord.Client()
#app.event
async def on_voice_state_update(member, before, after):
username = str(member)
guild = app.get_guild(660213767820410893)
ch = guild.get_channel(660213767820410918)
if after.channel == ch:
channel = await guild.create_voice_channel(
name = (username+"'s Room"),
category = guild.get_channel(660213767820410908),
user_limit = 99,
overwrites = {member: discord.PermissionOverwrite(manage_channels=True)}
)
await member.move_to(channel)
Finally please check that the app is in the server and has the Move Members permission on the server, otherwise member.move_to will throw a discord.Forbidden error.
Related
Here's what I have so far:
import discord
client = discord.Client(intents=discord.Intents.default())
token = 'PRETEND MY BOT TOKEN IS HERE'
#client.event
async def on_ready():
print(f'{client.user} has connected to Discord!')
#client.event
async def on_user_update(before, after):
if after.id == PRETEND THE TARGET USERS ID IS HERE:
if before.status != after.status:
owner = client.get_user(PRETEND THE BOT OWNERS ID IS HERE)
await owner.send(f'{after.name} has changed their status from {before.status} to {after.status}')
client.run(token)
It just doesn't seem to be working.
Here's what I've tried so far:
Making it so that instead of sending a direct message to the bot owner, the message is instead printed in the terminal. Didn't seem to work.
Using the term 'activity' instead of 'status', though I'm not sure if that makes a difference.
Using on_user_update, on_member_update, and on_presence_update. To be honest I don't know the difference between the three and which I should be using.
Based on the on_ready() function, the bot seems to be up and running. I suppose I just can't get it to detect the change in custom status. Also, I'm not sure if I'm taking the right approach when it comes to sending a direct message.
I believe this should work:
import discord as dc
class MyClient(dc.Client):
ownerid = <your id here>
targetid = <target id here>
async def on_ready(self):
print(f'Logged on as {self.user}!')
async def on_presence_update(self, before: dc.Member, after: dc.Member):
if before.id != self.targetid:
return
owner = await self.fetch_user(self.ownerid)
msg = ""
# If a user changed their name or discriminator
if before.name != after.name or before.discriminator != after.discriminator:
msg += f"{before.name}#{before.discriminator} has changed their name to {after.name}#{after.discriminator}\n"
# If a user changed their status (Online, Idle, Do not disturb, Invisible)
if before.status != after.status:
msg += f"{after.name}#{after.discriminator} has changed their status to {after.status}\n"
# If a user changed their activity (The emoji with some text)
if before.activity != after.activity:
msg += f"{after.name}#{after.discriminator} has changed their activity to:\n{after.activity}"
if msg != "":
await owner.send(msg)
intents = dc.Intents.default()
intents.members = True
intents.presences = True
client = MyClient(intents=intents)
client.run('<your token here>')
You just need to use the on_presence_update event and its required intents (members and presences).
My bot is on multiple servers, and IĀ“m trying to setup a member list for each server. The code is supposed to check for a role update (All servers use the same role as a member role) and then post a list of members in a specific channel. Right now the code works up until updatemsg() is called. I get an error saying the guild can't be an integer. How would I fix this error?
def updatemsg():
role = "OfficialMember"
guild = 754778020639932516
channel = guild.get_channel(754778311573635213)
channel.send("\n".join(str(member) for member in role.members))
#bot.event
async def on_member_update(before, after):
if len(before.roles) < len(after.roles):
if newRole.name == "OfficialMember":
print("MemList Updated")
updatemsg()
else:
print("Not OfficialMember Role")
I was wondering how I can set a role for a member, after he reacted to an emoji.
I've tried several ways but it hasn't worked anything yet.
AttributeError: 'Guild' object has no attribute 'add_roles'
I always get this error, I tried to replace Guild with User, Payload or Member, but it doesn't find it anyway
I have two file in my 'cogs' folder:
ā¢ roles.py - Handles the message with reactions (This file works perfectly)
ā¢ reaction.py - 'Listen' to the reactions to the message
import discord
import asyncio
import emoji
from discord.ext import commands
from discord.utils import get
client = commands.Bot(command_prefix='/',preload=True)
class Reaction(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
guild_id = payload.guild_id
guild = self.client.get_guild(guild_id)
user_id = payload.user_id
user = self.client.get_user(user_id)
message_id = payload.message_id
channel = self.client.get_channel(payload.channel_id)
emoji = payload.emoji.name
if message_id == 809523588721934336 and emoji == "š" and user_id != 799612948213399572:
message = await channel.fetch_message(message_id)
await message.remove_reaction("š", user)
dev = get(guild.roles, id=799632281639321632)
await guild.add_roles(dev)
def setup(client):
client.add_cog(Reaction(client))
I think it makes sense, how are you supposed to add a role to a guild? You must add it to a discord.Member instance, you can get it with payload.member
dev = get(guild.roles, id=799632281639321632)
member = payload.member
await member.add_roles(dev)
Also remember that you must have intents.members enabled
Reference:
RawReactionAddEvent.member
Member.add_roles
In the API reference you can see that Guild does not have the method add_roles. Members do have that method.
I want to create a command through which i can get the server invite link by entering the guilds id.
Like
#bot.command()
async def createinvitelink(ctx,guildid):
pass
so whenever someone uses the command they have to enter any guild id where the bot is. And the bot will give the invite link to the user of that server.
So far i had wrote this code but it doen't works.
#client.command(name='dm')
async def dm(ctx, guild_id: int):
if ctx.author.id == owner:
guild = client.get_guild(guild_id)
guildchannel = guild.system_channel
invitelink = await guildchannel.create_invite(max_uses=1,unique=True)
await ctx.author.send(invitelink)
Can someone help me how can i do that?
The problem here is that system_channel can be None sometimes. So just get 1st channel from the server's channels and create its invite.
#client.command(name='dm')
async def _dm(ctx, guild_id: int):
guild = client.get_guild(guild_id)
channel = guild.channels[0]
invitelink = await channel.create_invite(max_uses=1)
await ctx.author.send(invitelink)
#client.command()
async def createinvite(ctx, guildid: int):
try:
guild = client.get_guild(guildid)
invitelink = ""
i = 0
while invitelink == "":
channel = guild.text_channels[i]
link = await channel.create_invite(max_age=300,max_uses=1)
invitelink = str(link)
i += 1
await ctx.send(invitelink)
except Exception:
await ctx.send("Something went wrong")
I guess I have to explain that don't I...let's see
We first receive the Guild ID and type hint it to integer coz we don't want a stringThen I created a blank string for the invite link and a random variable with its value set to 0Then we run a while loop and why we are doing is because it is not necessary that your bot will have invite perms for the first channel in the server, so what we want is that if the bot does not get the invite for the first channel, it tries the next, and the next till it has checked every channel in the server. Only then can you say that your bot can't get an invite to the serverAnyways, so we check the text channels and set the value of our invitelink variable to whatever string output we get. This will go on till the bot actually finds an invite. If it doesn't we get an exception
I simply want my bot to add a role to a user in discord. Although the syntax seems simply, apparently I'm doing something wrong.I'm new to python, so I'd appreciate some pointers in the right direction!
bot = commands.Bot(command_prefix='!')
def getdiscordid(discordname):
for guild in bot.guilds:
for member in guild.members:
if member.name == discordname:
return member.id
#bot.command(name='role')
async def role(ctx):
await ctx.message.channel.send("Testing roles")
discordid = getdiscordid("Waldstein")
print ("id: " , discordid)
member = bot.get_user(discordid)
print ("member: ", member)
role = get(ctx.message.guild.roles, name="Egg")
print("role: ", role.name)
await member.add_roles(role)
print("done")
# error handler
#bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.errors.CheckFailure):
await ctx.send(error)
bot.run(TOKEN)
In this example he successfully retrieves the member, he can't find the Egg role, and doesn't add the role. [Edit: I corrected the line to retrieve the role, that works but still no added role. Added the error handler]
The key issue is that add_roles() adds roles to a Member object not a user.
Made a couple of tweaks...
Changed the get id to get member and return the member object.
changed the name of the command to add_role() to avoid using role as the command and a variable.
changed to await member.add_roles(role)
Try:
def get_member(discordname):
for guild in bot.guilds:
for member in guild.members:
if member.name == discordname:
return member
#bot.command(name='add_role')
async def add_role(ctx):
await ctx.message.channel.send("Testing roles")
member = get_member("Waldstein")
print(f'member is {member} type {type(member)}')
role = get(ctx.guild.roles, name="Egg")
print("role: ", role.name)
await member.add_roles(role)
print("done")
For the answer's sake, I'm writing the whole discord.utils.get instead of just get. Here's your command rewritten:
import discord
#bot.command()
async def role(ctx):
await ctx.send("Testing roles!")
member = discord.utils.get(bot.get_all_members(), name="Waldstein")
# be careful when getting objects via their name, as if there are duplicates,
# then it might not return the one you expect
print(f"id: {member.id}")
print(f"member: {member}")
role = discord.utils.get(ctx.guild.roles, name="Egg") # you can do it by ID as well
print(f"role: {role.name}")
await member.add_roles(role) # adding to a member object, not a user
print("Done!")
If this doesn't work, try printing out something like so:
print(ctx.guild.roles)
and it should return each role that the bot can see. This way you can manually debug it.
One thing that might cause this issue is that if the bot doesn't have the necessary permissions, or if its role is below the role you're attempting to get i.e. Egg is in position 1 in the hierarchy, and the bot's highest role is in position 2.
References:
Guild.roles
Client.get_all_members()
Member.add_roles()
utils.get()
commands.Context - I noticed you were using some superfluous code, take a look at this to see all the attributes of ctx