How to detect if a user join in anyone of voice channel? - python-3.x

I would simply like that when a specific user enters any voice chat on my discord server, my bot will detect it and then go into voice and say "x user joined the chat or something like this" (I already know how). The question is how to detect the user entering? (Detection must be instant).
I tried to using this code:
#bot.event
async def on_voice_state_update(message, after, before, member):
ctx = await bot.get_context(message)
u = ctx.guild.get_member(428938023057620994)
for channel in ctx.guild.voice_channels:
if sebastiano in channel:
tts = gTTS(text=u + "in voice chat", lang='en')
tts.save("u.mp3")
try:
vc = await channel.connect()
await vc.play(discord.FFmpegPCMAudio('sebastiano.mp3'))
await vc.disconnect()
except:
await ctx.send("Scusate ho la 104 e non funziono.")
But doesn't work:
File "/home/diego/Documents/Python 3/CancerBot/cancerbot.py", line 26, in on_voice_state_update
ctx = await bot.get_context(message)
File "/home/diego/.local/lib/python3.9/site-packages/discord/ext/commands/bot.py", line 880, in get_context
view = StringView(message.content)
AttributeError: 'Member' object has no attribute 'content'

you have some problems here:
there is no message or ctx in an on_voice_state_update.
the parameters have to be as follow:
member - the member who joined/left/moved channel
before - the voice state before. if he had entered a channel and didn't move from one channel to another, the channel attribute would be None
after - the voice state after. if he left a channel and didn't move channels the channel attribute would be None
you answer your question to check if someone has joined I would do it also if he moved I would do:
if after.channel:
then do what you've wanted

Related

Echo a message from another app in discord

I have a bot running in a separate app, but there is a specific variable holding data that I want to also be echo'd on my discord server. The bot itself is huge, but I can pin the specific method here
import discord
import asyncio
import rpChat
global note
class EchoBot(rpChat.ChatClient):
def on_PRI(self, character, message):
super().on_PRI(character, message)
note = character + ": " + message
global note
if message[:1] == "~":
super().PRI("A GameMaster", note)
to try to send this message to discord, I have the following. This is not put in the class above, but just below it, and is not in a class itself:
client = discord.Client()
async def discordEcho():
"""Background task that sends message sent from chat to an appropriate Discord channel
when global messege data is updated"""
await client.wait_until_ready()
channel = client.get_channel(serverroom}
while not client.is_closed():
global note
await channel.send(channel, note)
The data to grab the channel IDs are found in a json
file = open("credentials.json", "r", encoding="utf-8")
info = json.load(file)
file.close()
token = info["discord"]
serverroom = info["serverroom"]
client.loop.create_task(discordEcho())
client.run(token)
When I try this, I obtain:
await client.send_message(channel, message)
AttributeError: 'Client' object has no attribute 'send_message'
And I am unsure why. I have built a bot for both this chat platform, and for discord, but this is the first time I've ever attempted to bridge messages between the two. I am sure what I have offered is clear as mud, but any help would be appreciated, if possible.
Edit:
Edited changes to code. It is working thanks to comment below.
client.send_message is an old, outdated method, it has been replaced with Messageable.send
async def discordEcho():
"""Background task that sends message sent from chat to an appropriate Discord channel
when global messege data is updated"""
await client.wait_until_ready()
channel = client.get_channel(serverroom)
while not client.is_closed():
global note
await channel.send(note)
Side note: you first need to wait_until_ready before getting the channel to wait until the cache is done loading, otherwise channel will be None

Check TextChannel's id and do some actions

Hey everyone I want to delete all messages from a specific text channel I use this method
#client.event
async def on_message(message):
for guild in client.guilds:
for channel in guild.text_channels:
if channel.id == 818522056261369906:
await message.delete()
it works but it delete all text channels messages not just that text channel with the id above
What is the problem
it works but it delete all text channels messages not just that text channel with the id above What is the problem
You're deleting the message upon checking if a certain channel exists in your bot (i.e by checking if that channel exists in any of all the guilds your bot is in). You're not checking if the message's channel's id matches the provided ID or not. That's why it only checks if that specific channel exists and continues to delete the message regardless of weather they're in that specific channel or not.
for channel in guild.text_channels:
# you're checking if a certain channel in guild's
# text_channel matches the ID or not
if channel.id == 818522056261369906:
await message.delete()
But you ought to check if your message's channel's id matches the ID or not. You can do so by message.channel.id == 818522056261369906. So your code should look something like this
if message.channel.id == 818522056261369906:
await message.delete()
The simplest way to do this would be to include get_channel(id) and await purge if you want to continuously delete messages from a channel.
#client.event
async def on_message(message):
channel = client.get_channel(818522056261369906) # this gets the specific channel through id
await channel.purge()
await client.process_commands(message)
However, if you only want to purge it once in a given channel, you would use a #client.command with similar code as above.
#client.command()
async def test(ctx):
channel = ctx.channel # getting the current channel
await channel.purge()
Edit: Don't forget to add your await client.process_commands(message) if you're using both the commands extension and the on_message event!

How do I add a reaction emoji to the message the bot sends after doing the user's command?

I get this error: discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Bot' object has no attribute 'message'--when trying to do await self.client.message.add_reaction(emoji).
I tried changing it to await ctx.message.add_reaction(emoji), and I realized that it reacted to the command the user sent rather than the bot's new message.
import discord
from discord.ext import commands
class MovieNight(commands.Cog):
"""Polls for Movie Night."""
def __init__(self, client):
self.client = client
#commands.command(aliases=['m'])
async def movie(self, ctx, year, *movie):
movie_title = ' '.join(movie[:-1])
await ctx.send(f"`{year}` - `{movie_title}` | **{movie[-1]}**")
emoji = '👎'
await self.client.message.add_reaction(emoji)
def setup(client):
client.add_cog(MovieNight(client))
self.client doesn't know about the message, the is stored as part of the invocation context:
await ctx.message.add_reaction(emoji)
Adding onto Patrick's answer here from what you said in the comment.
await self.client.message.add_reaction(emoji) won't work because the bot doesn't know what message you're referring to, and client doesn't have an attribute called message.
Adding reactions requires a discord.Message object, which in your case can be either the command that the user executed (e.g. !movie 2020 movie title) which you can retrieve via ctx.message, or a message which you're making the bot send.
If you wanted to get the message object from the message that the bot sent, you can assign it to a variable:
msg = await ctx.send(f"`{year}` - `{movie_title}` | **{movie[-1]}**")
And this allows you to then add a reaction to it or access any other message attributes you would like:
emoji = '👎'
await msg.add_reaction(emoji)
References:
discord.Message
Message.add_reaction()
TextChannel.send() - Here you can see it returns the message that was sent

Moving a user to the message author's voice channel

Trying to make my discord bot move a user to the voice channel that the message author is in. E.g. I write !move #john Then the bot would move "john" to my voice channel.
# command to move a user to current channel
#bot.command()
async def move(ctx,member:discord.Member=None):
channel= discord.utils.get(ctx.guild.voice_channels)
if not member:
await ctx.send("Who am I trying to move? Use !move #user")
await member.move_to(channel)
At the moment it moves the users, but only to the first voice channel in the server. How do I get it to move it to the author's voice channel?
The VoiceChannel the author is in is stored in ctx.author.voice.channel. Notably, .voice and .channel can be None, so we need check for that
#bot.command()
async def move(ctx,member:discord.Member=None):
if ctx.author.voice and ctx.author.voice.channel:
channel = ctx.author.voice.channel
else:
await ctx.send("You are not connected to voice!")
if not member:
await ctx.send("Who am I trying to move? Use !move #user")
await member.move_to(channel)

How would I make my bot made in discord.py create a text message with custom permissions?

So I have a discord bot made with python3.6, and I want him to create a text channel, but only for admins.
I know how to create a text channel using await client.create_channel(), but I do not know how would I set custom permissions and how would I send a message to it.
Thank you!
My code (in case you need it):
#client.event
async def discord.on_server_join(server):
await client.send_message(channel, "Thank you for using Phantom. From all the developers, we want to thank you, as we know there are thousands of other bots out there.")
await client.send_message(channel, "You should see that a new channel was created and is called \"Phantom\". That is the phantom moderation channel and is used for administrating your phantom instance.")
server = ctx.message.server
await client.create_channel(server, "Phantom", type=discord.ChannelType.text)
#client.event
async def on_message(message):
# The code continues here, but I think you only need the on_server_join function.
The documentation for create_channel provides a similar example. Below, it is updated to make the channel visible to any role with administrator permissions.
def overwrites(server):
invisible = discord.PermissionOverwrite(read_messages=False)
visible = discord.PermissionOverwrite(read_messages=True)
perms = [(server.default_role, invisible)]
for role in server.roles:
if role.permissions.administrator:
perms.append((role, visible))
return perms
#client.event
async def discord.on_server_join(server):
await client.send_message(channel, "Thank you for using Phantom. From all the developers, we want to thank you, as we know there are thousands of other bots out there.")
await client.send_message(channel, "You should see that a new channel was created and is called \"Phantom\". That is the phantom moderation channel and is used for administrating your phantom instance.")
server = ctx.message.server
channel = await client.create_channel(server, "Phantom", *overwrites(server), type=discord.ChannelType.text)
await client.send_message(channel, "Hello!")
The simplest way of doing this is trying to check the if a player has a specific role,
for instance, checking if the player has the admin role. Here's a example.
if message.content.lower().startswith('/admin'):
role = discord.utils.get(message.server.roles,id='420576440111726592') #Replace the numbers with your role's id
if "340682622932090890" in [role.id for role in message.author.roles]: #Do the same here
await client.send_message(message.channel, "Aye you have admin!")
else:
await client.send_message(message.channel, "You do not have permissions to do this command")
I'm not a expert and also haven't tested this out, So tell me if it doesn't work.

Resources