Well im trying to create a voice channel by command so i can join it.
And as soon i leave the channel its supposed to get deleted.
What i tried:
if message.content.startswith('/voice'):
guild = message.guild
voicechannel = await guild.create_voice_channel(f"{str(message.author)}")
await asyncio.sleep(5)
while True:
if len(voicechannel.voice_states) == 0:
await voicechannel.delete()
break
doesnt even work tho
I believe that your issue is that you are stuck in an infinite while True loop. I would first suggest that you switch to using discord.ext.commands, it simplifies the process of creating a Discord Bot by a great deal. If you were using discord.ext.commands.Bot, you would be able to use the wait_for() function to wait until the voice channel is empty.
from discord.ext.commands import Bot
client = Bot(command_prefix="/")
#client.command(name="voice")
async def voice(ctx):
guild = ctx.guild
voice_channel = await guild.create_voice_channel(f"{str(ctx.author)}")
def check(member, before, after):
return member == ctx.author and before.channel == voice_channel and after.channel is None
await client.wait_for("voice_state_update", check=check)
await voice_channel.delete()
client.run("TOKEN")
The only issue that I think could happen, is if the member never joins the voice channel. To counter this, we can set up another wait_for() function to determine if the member ever joins before waiting for the member to leave the voice channel.
from asyncio import TimeoutError
#client.command(name="voice")
async def voice(ctx):
guild = ctx.guild
voice_channel = await guild.create_voice_channel(f"{str(ctx.author)}")
def check(member, before, after):
return member == ctx.author and before.channel is None and after.channel == voice_channel
try:
await client.wait_for("voice_state_update", check=check, timeout=60)
except TimeoutError:
await voice_channel.delete()
return
Related
I know next to nothing about coding in Python but I created this bot from tutorials I found online and it does little things in my private server.
One thing we'd love to do is to react to certain messages so they will be collected in a specific channel. I've seen a few servers do this, like a highlights kind of thing.
I found something promising here in Stackoverflow but it's in javascript :<
Edit: 2023-01-19 08:53 GMT+8
#client.event
async def on_reaction_add(reaction, member):
if str(reaction.emoji) == "⭐":
channel = await bot.get_channel(channel_id)
await channel.send(reaction.message.content)
Final code
edited: 2023-01-20 17:14 GMT+8
#bot.event
async def on_reaction_add(reaction, user):
if reaction.emoji == "⭐":
astrometrics = bot.get_channel(channel id here)
embed = discord.Embed(color = 0xFEE75C)
embed.set_author(name = reaction.message.author.name, icon_url = reaction.message.author.display_avatar)
embed.add_field(name = "Message Content", value = reaction.message.content)
if len(reaction.message.attachments) > 0:
embed.set_image(url = reaction.message.attachments[0].url)
embed.add_field(name = "Go to message", value = reaction.message.jump_url, inline = False)
await astrometrics.send(embed = embed)
You can check certain messages in on_message event. And for getting a specific channel in your server, you need to have the channel id. link
Something like this:
#bot.event
async def on_message(message):
if message.content == 'the certain message':
specific_channel = await bot.get_channel(channel_id)
await specific_channel.send(message.content)
But this might have some rate-limited consequence if the 'certain message' was too much and sent at a high rate. (If yes, then there's nothing you can do since rate-limited is a discord limitation).
I'm making a discord bot and a problem that has come up for me is that the bot won't reply to the user, here is the code
#Code Imports
import discord
import random
from discord import message
from discord import channel
from discord.embeds import Embed
from discord.ext import commands
from discord.ext.commands.bot import Bot
from discord.message import Message
from apikeys import *
from discord import guild
from discord import emoji
from discord import *
from discord import ContentFilter
from discord import channel
from discord import client
#intents
intents=discord.Intents.default()
intents.members=True
#prefix
client=commands.Bot(command_prefix='!',intents=intents)
#Start
#client.event
async def on_ready():
for emoji in client.emojis:
print("Name:", emoji.name + ",", "ID:", emoji.id)
print('Bot is Online {0.user}'.format(client))
print("--------------------------------------------------------------------------------------------------------------------------------------------------------")
client.remove_command('help')
#Commands
#client.command()
async def work(ctx):
await ctx.send('use !war to get up the war menu')
emojigood = '\N{THUMBS UP SIGN}'
emojibad="\N{THUMBS DOWN SIGN}"
#client.command()
async def help(ctx):
embed=discord.Embed(title='Help', description='!war is currently under testing please do not complain about it', color=0x00000)
await ctx.send(embed=embed)
#client.command()
async def war(ctx):
embed = discord.Embed(title='War', description='You are starting a war, do you want to continue?', color=0x00000)
msg = await ctx.send(embed=embed)
await msg.add_reaction(emojigood)
await msg.add_reaction(emojibad)
def check(r, user):
return (r.emoji == emojigood or r.emoji == emojibad) and r.message == msg
#Checks whether the message is the same, and the emoji is one of the accepted ones, and returns either True or False
r, user = await client.wait_for('reaction_add',timeout=10 ,check=check)
#this is equivalent to a event listener within your command, it will stop there until a reaction that meets the requirements has been found
#(This won't block other commands and functions)
if r.emoji == emojigood:
embed = discord.Embed(title='War', description='Please now choose a country', color=0x00000)
await ctx.send(embed=embed)
prefix = "!" #insert your prefix
async def on_message(message):
if message.author == client.user:
return
if message.content == f'{prefix}war': #dont need to use this string, just illustrating the point
await message.channel.send("What country do you want to start a war with?")
def check(msg):
return msg.author == message.author and len(msg.role_mentions) > 0
msg = await client.wait_for('message', check=check)
role = msg.role_mentions[0]
channel = client.get_channel(849230881994047508)
await channel.send(f"{role.mention} {message.author} has declared war on you.")
client.run(token)
What's meant to happen:
Bot: Which role would you like to start a war with
User:#something
Bot:Send information to UN, 'War on #something'
I don't know how to make it see the role mention
You have a couple of issues, the way to make the code you're using function decently is to replace message.content with message.clean_content, however, 1. That will react to any message starting with # or a mention, which is probably not what you want, and 2. any message not beginning with the mention wouldn't work.
You say in your description that you're looking for role mentions, which is a different attribute, and you're looking to send a message, and wait for a response, so here's a piece of sample code that would solve those issues, assuming I'm interpreting your question correctly:
def check(msg):
return msg.author == message.author and len(msg.role_mentions) > 0
msg = await client.wait_for('message', check=check)
role = msg.role_mentions[0]
channel = client.get_channel(ID of the channel)
await channel.send(f"{role.mention} {message.author} has declared war on you."
If I misinterpreted any of what you wanted or you're not sure how some of it works, shoot me a comment and I'll do my best to explain!
Docs reference for slightly more complex objects used:
role_mentions,
wait_for(),
Here is what I got so far
It is saying that "await" is outside of async function and I am just confused on how to fix this. I copied part of the code from a giveaway command because that is my only source of Q&A code I have
#commands.has_permissions(administrator = True)
async def cdelete(ctx):
embed=discord.Embed(title = Which channel would you like to delete?)
await ctx.send(embed=embed)
answer = []
def check(m):
return m.author == cx.author and m.channel == ctx.channel
try:
await client.wait_for('message', timeout=15, check=check)
except asyncio.TimeoutError:
await ctx.send("Timeout. Please run the command again")
else:
answer.append(message.content)
try:
c_id= int(answer[0][2:-1])
await ctx.channel.delete
await ctx.send("Channel Deleted")
except:
await ctx.send("Thats not a valid channel!")```
If you just want a command you can make it a lot easier if you just execute a command with the channel name. You can have a look at the following:
#client.command()
#commands.has_permissions(administrator=True)
async def cdelete(ctx, channel_name):
"""Deletes a channel by name or ID."""
channel_id = int(''.join(i for i in channel_name if i.isdigit())) # Get channel ID
existing_channel = client.get_channel(channel_id) # Get channel ID with defined method
if existing_channel: # If channel with the name/ID exists
await existing_channel.delete()
else: # If the channel does not exist
await ctx.send(f'**No channel named `{channel_name}` was found.**')
We have a method to catch the channel ID and also pass that in as a valid argument. If the ID or channel name then exists we delete the channel.
You can here either mention the channel or pass in the ID.
Usage would be: cdelete #channel/ID.
If you want to avoid a long console output if you input no channel/ID/name you can build in an error handler:
#cdelete.error
async def cdelete_error(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send("You need to name a channel.")
The problem you have here is with the check() function. According to the doc you only can use await inside of an async function. To solve the problem change def check(m): into async def check(m):
So I am working on a little project here, and pretty much, I want to have one of those "Please type the name of a channel in this server" feature.
So pretty much, the bot asks for a channel name, and I put in for example "#changelog" - and then it will ask for what it should write in that channel, etc etc.
So need to get the channel id (I am guessing), but I don't want users to write the ID, instead only writing the #server-name. And then whenever I have done that, the bot shall write in that channel.
Here is my current code!
class Changelog(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print('Changelog is loaded')
#commands.command()
async def clhook(self, ctx):
await ctx.send('Write text-channel: ')
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
clhook = self.client.get_channel(text_channel)
def setup(client):
client.add_cog(Changelog(client))
Edit:
The channel ID shall be saved "forever", meaning that I do not have to re-write the channel name where the message should go!
You can use discord.utils.get() with this example:
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
channel = discord.utils.get(ctx.guild.text_channels, name=text_channel)
await channel.send('Bla Bla')
So when you type (prefix)clhook then only the channel name, for example general, it will send Bla Bla to the channel named general .
There is another way to do this and I think it's simple than the first option, here it is:
#commands.command()
async def clhook(self, ctx, channel: discord.TextChannel):
await channel.send('Bla Bla')
So in this command, usage is changed. You can use that with this: (prefix)clhook #general(mention the channel). I suggest this solution and I think it's more useful.
You can use message.channel_mentions. This will return a list of all channels that were mentioned using the #channel-name notation. That way, you can just use channel.id to get the id of the channel they mentioned.
Don't forget, however, to check if the user did in fact tag a channel (which you can also put in your check). I put it in a separate function to make it a bit more readable for the sake of this reply, but you can fit that in your lambda if you really want to.
Also, make sure to check if it's a Text Channel and not a Voice Channel or Category Channel.
#commands.command()
async def clhook(self, ctx):
def check(self, message):
author_ok = message.author == ctx.author # Sent by the same author
mentioned_channel = len(message.channel_mentions) == 1 and isinstance(message.channel_mentions[0], discord.TextChannel)
return author_ok and mentioned_channel
await ctx.send("Write text-channel: ")
text_channel = await self.client.wait_for("message", check=check)
chlhook = text_channel.channel_mentions[0]
I put two conditions on the mentioned_channel line, because if the first one fails, the second one could cause an IndexError. Alternatively you can also use an if-statement to return sooner at that place to solve the same issue.
I'm trying to get my discord bot to connect to a voice channel like this currently:
#client.event
async def on_message(message):
message.content = message.content.lower()
if message.author == client.user:
return
if '-skip' in message.content:
await message.author.channel.connect
await message.channel.send (f"-p scotland forever")
await disconnect
Basically I want it to join a voice channel from the message author when they send the message "-skip" and then my bot joins, says -p scotland forever in chat, and then leaves. I get an error message saying things like "channel" not defined or "connect" not defined, ive tried doing it a few different ways, I think i just havent imported a plugin or whatever and thats probably my issue, but idk what plugin thing to use. Any help would be appreciated.
Try this:
#client.event
async def on_message(message):
message.content = message.content.lower()
if message.author == client.user:
return
if '-skip' in message.content:
channel = message.author.voice.channel
if channel is not None:
await channel.connect()
await message.channel.send (f"-p scotland forever")
await client.voice_clients[0].disconnect()
else:
await message.channel.send ("You need to join to voice channel")
Try this
#commands.command()
async def join_voice(self, ctx):
connected = ctx.author.voice
if connected:
await connected.channel.connect(put vc id here)
It may work
I guess?