I am making a Discord Bot that plays music when I give it the name of a song.
Whenever I give it the ".play" command, the Discord app shows that the bot is in fact playing audio, I just don't hear any.
I tried multiple times with different music, however I recieved the same problem.
Here is my code:
import discord
from discord.ext import commands
import wavelink
client = commands.Bot(command_prefix = ".", intents = discord.Intents.all())
class CustomPlayer (wavelink.Player):
def __init__(self):
super().__init__()
self.queue = wavelink.Queue()
#client.event
async def on_ready():
client.loop.create_task(connect_nodes()) #HTTPS and Websocket operations
async def connect_nodes(): #Helper function
await client.wait_until_ready()
await wavelink.NodePool.create_node(
bot = client ,
host = "127.0.0.1" ,
port = 2333 ,
password = "youshallnotpass"
)
#client.event
async def on_wavelink_node_ready(node = wavelink.Node):
print(f"Node: <{node.identifier}> is ready!")
#client.command()
async def connect(ctx):
vc = ctx.voice_client
try:
channel = ctx.author.voice.channel
except AttributeError:
return await ctx.send("Please join a channel to connect.")
if not vc:
await ctx.author.voice.channel.connect(cls = CustomPlayer())
else:
await ctx.send("The bot is already connected to a voice channel.")
#client.command()
async def disconnect(ctx):
vc = ctx.voice_client
if vc:
await vc.disconnect()
else:
await ctx.send("Bot is not connected to a voice channel.")
#client.command()
async def play(ctx, *, search: wavelink.YouTubeTrack):
vc = ctx.voice_client #represents a discord voice connection
if not vc:
custom_player = CustomPlayer()
vc: CustomPlayer = await ctx.author.voice.channel.connect(cls = custom_player)
if vc.is_playing():
vc.queue.put(item = search)
await ctx.send(embed = discord.Embed(
title = search.title,
url = search.uri,
description = f"Queued {search.title} in {vc.channel}"
))
else:
await vc.play(search)
await ctx.send(embed = discord.Embed(
title = search.title,
url = search.uri,
description = f"Playing {vc.source.title} in {vc.channel}"))
Related
I have a problem with my code from my discord bot. When I run the program I get an error message, but I have all imports up to date. Can someone help me please, because I really have no idea how to fix this . If you have any more questions just write in.
Here is the error:
AttributeError: module 'discord' has no attribute 'ui'
And Here is my Code:
import discord
from discord.ext import commands
from discord_ui import ButtonInteraction, Button, ButtonStyle, UI
intent = discord.Intents.default()
intent.members = True
bot = commands.Bot(command_prefix="!", intent=intent)
role_id = 938465872098512956
guild_id = 938215477157703771
class RoleButton(discord.ui.Button):
def __init__(self):
super().__init__(
label="Verifiziere dich hier!",
style=discord.enums.ButtonStyle.blurple,
custom_id="interaction:RoleButton",
)
async def callback(self, interaction: discord.Interaction):
user = interaction.user
role = interaction.guild.get_role(role_id)
if role is None:
return
if role not in user.roles:
await user.add_roles(role)
await interaction.response.send_message(f"🎉 Du bist nun verifiziert!", ephemeral=True)
else:
await interaction.response.send_message(f"❌ Du bist bereits verifiziert!", ephemeral=True)
BILD_URL = ""
BESCHREIBUNG = "Test"
#bot.command()
async def post(ctx: commands.Context): # Command
view = discord.ui.View(timeout=None)
view.add_item(RoleButton())
await ctx.send(f"{BILD_URL}")
await ctx.send(f"{BESCHREIBUNG}", view=view)
#bot.event
async def on_ready():
print("ONLINE!")
view = discord.ui.View(timeout=None)
view.add_item(RoleButton())
bot.add_view(view)
bot.run("")
I'm new to python, so I wonder if there's a way to do so.
Here's my play mp3 command:
#bot.command()
async def play_song1(ctx):
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()
voice.play(discord.FFmpegPCMAudio('./mp3/song1.mp3'))
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.1
await ctx.send ('playing')
while voice.is_playing():
await asyncio.sleep(.1)
await voice.disconnect()
I made 2 more same commands but for song2 and song3, and now I want to queue the mp3 when someone calls them.
Seen as if you're not using cogs, you could try something like this:
guild_queues = {} # Multi-server support as a dict, just use a list for one server
# EDIT: Map song names in a dict
play_messages = {
"song1": "Now playing something cool!",
"song2": "And something even cooler just started playing!",
"song3": "THE COOLEST!"
}
async def handle_queue(ctx, song):
voice = discord.utils.get(bot.voice_clients, guild=ctx.guild)
channel = ctx.author.voice.channel
if voice and channel and voice.channel != channel:
await voice.move_to(channel)
elif not voice and channel:
voice = await channel.connect()
if not voice.is_playing():
audio = discord.FFmpegPCMAudio(f"./{song}.mp3")
source = discord.PCMVolumeTransformer(audio)
source.volume = 0.1
voice.play(audio)
await ctx.send(play_messages[song])
while voice.is_playing():
await asyncio.sleep(.1)
if len(guild_queues[ctx.guild.id]) > 0:
next_song = guild_queues[ctx.guild.id].pop(0)
await handle_queue(ctx, next_song)
else:
await voice.disconnect()
#bot.command()
async def play(ctx, *, song): # I'd recommend adding the filenames as an arg, but it's up to you
# Feel free to add a check if the filename exists
try:
# Get the current guild's queue
queue = guild_queues[ctx.guild.id]
except KeyError:
# Create a queue if it doesn't already exist
guild_queues[ctx.guild.id] = []
queue = guild_queues[ctx.guild.id]
voice = discord.utils.get(bot.voice_clients, guild=ctx.guild)
queue.append(song)
# The one song would be the one currently playing
if voice and len(queue) > 0:
await ctx.send("Added to queue!")
else:
current_song = queue.pop(0)
await handle_queue(ctx, current_song)
References:
utils.get()
Client.voice_clients
Context.guild
Member.voice
VoiceState.channel
VoiceClient.move_to()
VoiceClient.is_playing()
VoiceClient.play()
discord.FFmpegPCMAudio()
discord.PCMVolumeTransformer()
Context.send()
My Current Project
I am currently trying to make a cog for a Discord bot in Python 3 that, when running, plays a specific audio file when someone joins a specific Discord voice channel.
My Problem
I already have the code for my project(credit: Tabulate), but I don't know how to
Convert it to a cog, and
Make it work for a specific voice channel, and not every one in the Discord
server.
Here's my code:
import discord
from discord.ext import commands
from time import sleep
rpgmusicpath = r"C:\Users\lones\OneDrive\Desktop\Bot\music\rpgmusic.mp3"
class VoiceChannelIntro(commands.Cog):
def __init__(self, client):
self.bot = client
#commands.Cog.listener()
async def on_ready(self):
print('Channel Intro cog successfully loaded.')
#commands.Cog.event
async def on_voice_state_update(member: discord.Member, before, after):
#replace this with the path to your audio file
path = r"path\to\music.mp3"
vc_before = before.channel
vc_after = after.channel
if vc_before == vc_after:
return
elif vc_before is None:
channel = member.voice.channel
vc = await channel.connect()
vc.play(discord.FFmpegPCMAudio(path))
with audioread.audio_open(path) as f:
#Start Playing
sleep(f.duration)
await vc.disconnect()
elif vc_after is None:
return
else:
channel = member.voice.channel
vc = await channel.connect()
vc.play(discord.FFmpegPCMAudio(path))
with audioread.audio_open(path) as f:
#Start Playing
sleep(f.duration)
await vc.disconnect()
def setup(bot):
bot.add_cog(VoiceChannelIntro(bot))
Here are some of your mistakes:
Use asyncio.sleep() instead of time.sleep()
You forgot to pass self as the first argument
Below is the revised code:
import discord
from discord.ext import commands
from asyncio import sleep
rpgmusicpath = r"C:\Users\lones\OneDrive\Desktop\Bot\music\rpgmusic.mp3"
class Music(commands.Cog):
def __init__(self, client):
self.bot = client
#commands.Cog.listener()
async def on_ready(self):
print('Music cog successfully loaded.')
#commands.Cog.event
async def on_voice_state_update(self, member, before, after):
#replace this with the path to your audio file
path = r"C:\Users\lones\OneDrive\Desktop\Bot\test-chamber-4-intro.mp3"
vc_before = before.channel
vc_after = after.channel
if not vc_before and vc_after.id == YOUR VOICE CHANNEL ID:
vc = await vc_after.connect()
vc.play(discord.FFmpegPCMAudio(path))
with audioread.audio_open(path) as f:
#Start Playing
sleep(f.duration)
await vc.disconnect()
def setup(bot):
bot.add_cog(Music(bot))
-----Play Section this works well-----
async def play(self, ctx, *, arg):
await ctx.channel.purge(limit=1)
try: channel = ctx.author.voice.channel
except: await ctx.send("❌ You're not connected to any channel!", delete_after = 5.0)
else:
channel = ctx.author.voice.channel
voice = get(self.bot.voice_clients, guild=ctx.guild)
song = Music.search(ctx.author.mention, arg)
------queue section------
if voice and voice.is_connected():
await voice.move_to(channel)
else:
voice = await channel.connect()
if not voice.is_playing():
self.song_queue[ctx.guild] = [song]
self.message[ctx.guild] = await ctx.send(embed=song['embed'])
voice.play(discord.FFmpegPCMAudio(song['source'], **Music.FFMPEG_OPTIONS), after=lambda e: self.play_next(ctx))
voice.is_playing()
else:
self.song_queue[ctx.guild].append(song)
await self.edit_message(ctx)
----stop section----
only skips music and don't clear queue
i don't know what is wrong here
#commands.command(brief='$stop')
async def stop(self, ctx):
voice = get(self.bot.voice_clients, guild=ctx.guild)
channel = ctx.message.author.voice.channel
await ctx.channel.purge(limit=1)
if voice and voice.is_playing():
await ctx.send('⛔ Music Stopped', delete_after = 5.0)
voice.stop(ctx.guild)
else:
await ctx.send("❌ I'm not playing any songs!", delete_after = 5.0)
My Current Project
I'm trying to convert a Python music bot I made off a YouTube video into a cog, so my main Python Discord bot file isn't so cluttered.
My Problem
The code below I wrote isn't working. I read the docs on cogs, but I can't seem to find what I did wrong.
Here's the code I tried making, but it
import discord
from discord.ext import commands
from discord.utils import get
import youtube_dl
import os
from time import sleep
rpgmusicpath = r"path\to\music.mp3"
class Music(commands.Cog):
def __init__(self, client):
self.bot = client
#commands.Cog.listener()
async def on_ready(self):
print('Music cog successfully loaded.')
#commands.command(pass_context=True)
async def rpgmusic(ctx, self):
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'Bot connected to voice channel {channel}\n')
await ctx.send(f'Playing some RPG music in {channel}.')
sleep(3)
voice.play(discord.FFmpegPCMAudio('rpgmusic.mp3'), after=lambda e: print(f'RPG music in {channel} has finished playing.'))
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.05
#commands.command(pass_context=True)
async def join(ctx, self):
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'Bot connected to voice channel {channel}\n')
await ctx.send(f'I joined {channel}.')
#commands.command(pass_context=True)
async def leave(ctx, self):
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'Bot disconnected from channel {channel}.')
else:
print('Not able to disconnect to a voice channel because bot wasn\'t in one.')
#commands.command(pass_context=True)
async def play(ctx, url: str, self):
song_there = os.path.isfile('song.mp3')
try:
if song_there:
os.remove('song.mp3')
print('Removed current song.')
except PermissionError:
print('Error in deleting song file. (Song in use.)')
await ctx.send('Unable to request song. (Song already in use.)')
return
await ctx.send('Preparing song. Please wait.')
voice = get(bot.voice_clients, guild=ctx.guild)
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
print('Downloading audio now.\n')
ydl.download([url])
for file in os.listdir('./'):
if file.endswith('.mp3'):
name = file
print(f'Renamed File: {file}.')
os.rename(file, 'song.mp3')
voice.play(discord.FFmpegPCMAudio('song.mp3'), after=lambda e: print(f'{name} has finished playing.'))
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.06
nname = name.rsplit('-', 2)
await ctx.send(f'Now playing {name}.')
print('Now playing.\n')
def setup(bot):
bot.add_cog(Music(bot))
Two problems :
You didn't replaced bot by self.bot.
In rpgmusic, join, leave and play commands, change :
voice = get(bot.voice_clients, guild=ctx.guild)
To :
voice = get(self.bot.voice_clients, guild=ctx.guild)
Your first argument must be self, and not ctx:
#commands.command(pass_context=True)
async def rpgmusic(self, ctx)
#commands.command(pass_context=True)
async def join(self, ctx)
#commands.command(pass_context=True)
async def play(self, ctx)
Also, since you have a join function, you can await it in rpgmusic (you also don't need global voice):
#commands.command(pass_context=True)
async def rpgmusic(ctx, self):
await self.join(ctx)
await ctx.send(f'Playing some RPG music in {channel}.')
sleep(3)
voice.play(discord.FFmpegPCMAudio('rpgmusic.mp3'), after=lambda e: print(f'RPG music in {channel} has finished playing.'))
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.05