I'm trying to make a discord bot. It works fine for responding to certain messages, which is part of what I wanted it to do. I now want it to be able to join the voice channel, but it wont:
import discord
import youtube_dl
from discord.ext import commands
from discord.utils import get
TOKEN = 'token string here
BOT_PREFIX = '/'
bot = commands.Bot(command_prefix=BOT_PREFIX)
players = {}
#bot.event
async def on_ready():
print(bot.user.name + ' is now online.\n')
and then after my message handling #bot.event,
#bot.command(pass_context=True)
async def join(ctx):
print('Join executed')
global voice
channel = ctx.message.author.voice.channel
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_connected():
await voice.move_to(channel)
else:
voice = await channel.connect()
print (f"The bot has joined {channel}\n")
#bot.command(pass_context=True)
async def leave(ctx):
channel = ctx.message.author.voice.channel
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_connected():
await voice.disconnect()
print(f"The bot has left {channel}")
else:
print("Bot was asked to leave, but was not in one.")
I'm very new, so it could be (or probably is) a very simple, stupid fix.
The join command isn't even being processed, as that print statement isn't showing up in console when I call it in the discord chat.
I was following this video tutorial to a T, and his clearly works fine.
I think you just got on_message event. If you do, check this docs page.
Also i have no idea why you passed pass_context they removed it at version 1.0, and it doesn't even exist now.
Check below. This will work with the latest version of discord.py.
#bot.command(name='join', invoke_without_subcommand=True)
async def join(ctx):
destination = ctx.author.voice.channel
if ctx.voice_state.voice:
await ctx.voice_state.voice.move_to(destination)
return
ctx.voice_state.voice = await destination.connect()
await ctx.send(f"Joined {ctx.author.voice.channel} Voice Channel")
Related
Here's the code:
import discord
from discord.ext import commands
from discord.utils import get
TOKEN = ""
BOT_PREFIX = "!"
bot = commands.Bot(command_prefix=BOT_PREFIX)
#bot.command(pass_context=True, brief="Makes the bot join your channel", aliases=['j', 'jo'])
async def join(ctx):
channel = ctx.message.author.voice.channel
print(channel)
voice = await channel.connect()
When I joined a voice channel, I joined the command, and it printed "music". When I tried again, it printed "music" and sent in error: discord.errors.ClientException: Already connected to a voice channel.
What should I do?
You can use a try-except statement to catch the error, or you can use an if statement to just check if the bot is already connected to a voice channel.
try:
voice = await channel.connect()
except:
print("Bot already connected")
It only mutes me and itself when it shouldn't, bot has highest role and also has permission in joined voice channel. any ideas?
#bot.command()
async def mute(ctx):
voice_client = ctx.guild.voice_client #
if not voice_client:
return
channel = voice_client.channel
people = channel.members
for person in people:
if person == client.user:
continue
await person.edit(mute=True, reason="{} told me to mute everyone in this channel".format(ctx.author))
edit Full code:
import discord
from discord.ext import commands
import os
from discord.utils import get
client = discord.Client()
DISCORD_TOKEN = os.getenv("TokenGoesHere")
bot = commands.Bot(command_prefix="$")
#client.event
async def on_ready():
print('BOT ACTIVATED')
#bot.command()
async def join(ctx):
channel = ctx.message.author.voice.channel
await channel.connect()
#bot.command()
async def disconnect(ctx):
channel = ctx.message.author.voice.channel
await channel.disconnect()
#bot.command()
#commands.has_permissions(administrator=True)
async def mute(ctx):
voice_client = ctx.guild.voice_client #get bot's current voice connection in this guild
if not voice_client: #if no connection...
return #probably should add some kind of message for the users to know why nothing is happening here, like ctx.send("I'm not in any voice channel...")
channel = voice_client.channel #get the voice channel of the voice connection
people = channel.members #get the members in the channel
for person in people: #loop over those members
if person == client.user: #if the person being checked is the bot...
continue #skip this iteration, to avoid muting the bot
await person.edit(mute=True, reason="{} told me to mute everyone in this channel".format(ctx.author))
#edit the person to be muted, with a reason that shows in the audit log who invoked this command. Line is awaited because it involves sending commands ("mute this user") to the server then waiting for a response.
#bot.command()
#commands.has_permissions(administrator=True)
async def unmute(ctx):
voice_client = ctx.guild.voice_client
if not voice_client:
return
channel = voice_client.channel
people = channel.members
for person in people:
if person == client.user:
continue
await person.edit(mute=False, reason="{} told me to mute everyone in this channel".format(ctx.author))
bot.run("TokenGoesHere")
Hope this helps, Bot sometimes mutes only itself or only itself and other user, but specifically that one user...
It only mutes me and itself when it shouldn't, bot has highest role and also has permission in joined voice channel. any ideas?
You have to define the intents to use some events, functions like on_message, guild.members, channel.members etc.
# Here is your imports
import discord
intents = discord.Intents().all()
bot = commands.Bot(command_prefix='', intents=intents)
# Rest of your code
Also, you have to activate intents from Discord Developer Portal.
Go to your bot application.
Go to Bot -> Privileged Gateway Intents.
Activate Presence Intent and Server Members Intent.
I've made these two commands, one for leaving the channel that the bot is currently connected to, and one for joining the command sender's channel.
The problem is that neither of them are working. How can I fix this?
#bot.command(pass_context=True)
async def leave(ctx):
server = ctx.message.guild.voice_client
await server.disconnect()
#bot.command(pass_context = True)
async def join(ctx):
channel = ctx.message.author.voice.voice_channel
await bot.join_voice_channel(channel)
It looks as though you're using old documentation or tutorials, along with some new documentation.
Some changes from 0.16.x to rewrite:
You should use VoiceChannel.join() instead of Client.join_voice_channel()
Shortcuts are available when using Context. In your case, ctx.guild instead of ctx.message.guild.
All voice changes
Context is automatically passed - there isn't any need for pass_context=True
Rewriting your code - with some conditions to check if the author is in a voice channel:
#bot.command()
async def leave(ctx):
if ctx.guild.voice_client.is_connected(): # Checking that they're in a vc
await ctx.guild.voice_client.disconnect()
else:
await ctx.send("Sorry, I'm not connected to a voice channel at the moment.")
#bot.command()
async def join(ctx):
if ctx.author.voice:
await ctx.author.voice.channel.connect() # This will error if the bot doesn't have sufficient permissions
else:
await ctx.send("You're not connected to a channel at the moment.")
References:
New documentation
VoiceClient.is_connected()
VoiceClient.disconnect()
Context.send()
Member.voice
VoiceState.channel
VoiceChannel.connect()
I've made bot to join my voice server like below
if message.content.startswith("?join"):
channel = message.author.voice.channel
await channel.connect()
await message.channel.send('bot joined')
but i can't make bot to leave the channel.. how can i code to do it??
and what is the difference between
#bot.event
async def on_message(message):
if message.content.startswith('~'):
and
#bot.command()
async def ~(ctx):
You can do both of these commands (the join and leave channel commands) in two ways, one is by using on_message, and the other is by using #bot.commands. It's is best to use bot.command instead of on_message for commands as bot.commands has more features plus I think it's fast after all it was built for commands. So I'll rewrite both of your commands using bot.command and also put using on_message there incase you don't want to use bot.command.
According to your message, I'm assuming ? is your prefix
Using on_message
#bot.event
async def on_message(message):
if (message.content.startswith('?join')):
if (message.author.voice): # If the person is in a channel
channel = message.author.voice.channel
await channel.connect()
await message.channel.send('Bot joined')
else: #But is (s)he isn't in a voice channel
await message.channel.send("You must be in a voice channel first so I can join it.")
elif message.content.startswith('?~'): # Saying ?~ will make bot leave channel
if (message.guild.voice_client): # If the bot is in a voice channel
await message.guild.voice_client.disconnect() # Leave the channel
await message.channel.send('Bot left')
else: # But if it isn't
await message.channel.send("I'm not in a voice channel, use the join command to make me join")
await bot.process_commands(message) # Always put this at the bottom of on_message to make commands work properly
Using bot.command
#bot.command()
async def join(ctx):
if (ctx.author.voice): # If the person is in a channel
channel = ctx.author.voice.channel
await channel.connect()
await ctx.send('Bot joined')
else: #But is (s)he isn't in a voice channel
await ctx.send("You must be in a voice channel first so I can join it.")
#bot.command(name = ["~"])
async def leave(ctx): # Note: ?leave won't work, only ?~ will work unless you change `name = ["~"]` to `aliases = ["~"]` so both can work.
if (ctx.voice_client): # If the bot is in a voice channel
await ctx.guild.voice_client.disconnect() # Leave the channel
await ctx.send('Bot left')
else: # But if it isn't
await ctx.send("I'm not in a voice channel, use the join command to make me join")
Save the channel connection, so you can disconnect later.
voice = None
...
if message.content.startswith("?join"):
channel = message.author.voice.channel
global voice = await channel.connect()
await message.channel.send('bot joined')
elif message.content.startswith("?join"):
await self.voice.disconnect()
Anyways, try using the discord.ext.commands extension. It makes everything involving commands easier. I'd also recommend using cogs (example), as you can just have a class with everything voice-related, and you don't need global variables.
#client.command(pass_context=True)
async def joinvoice(ctx):
"""Joins user's voice channel"""
author = ctx.message.author
voice_channel = author.voice_channel
vc = await client.join_voice_channel(voice_channel)
That is how I currently make the bot join a voice channel, how would I make it play an audio file as it joins? I have almost 0 experience, so far the entire bot has been coded by asking questions and a LOT of googling. Any help is much appreciated, thanks!
You have to create a StreamPlayer and use the player operations to play the audio. Heres some example code I wrote to play a vuvuzela with my discord bot:
#client.command(
name='vuvuzela',
description='Plays an awful vuvuzela in the voice channel',
pass_context=True,
)
async def vuvuzela(context):
# grab the user who sent the command
user = context.message.author
voice_channel = user.voice.voice_channel
channel = None
if voice_channel != None:
channel = voice_channel.name
await client.say('User is in channel: ' + channel)
vc = await client.join_voice_channel(voice_channel)
player = vc.create_ffmpeg_player('vuvuzela.mp3', after=lambda: print('done'))
player.start()
while not player.is_done():
await asyncio.sleep(1)
player.stop()
await vc.disconnect()
else:
await client.say('User is not in a channel.')