Switched Amber to do audio similar to another bot I've made.
This commit is contained in:
parent
215fad0471
commit
5a0cf3855d
153
audio.py
153
audio.py
@ -1,55 +1,34 @@
|
|||||||
import discord
|
import discord
|
||||||
import yt_dlp
|
import yt_dlp
|
||||||
|
import asyncio
|
||||||
|
|
||||||
voice_clients = {} # Track active voice connections
|
voice_clients = {} # Track active voice connections
|
||||||
|
music_queues = {} # Per-guild song queue
|
||||||
|
current_tracks = {} # Currently playing tracks
|
||||||
async def join_voice(interaction: discord.Interaction):
|
volumes = {} # Volume levels per guild
|
||||||
if interaction.user.voice is None or interaction.user.voice.channel is None:
|
default_volume = 0.5 # Default volume (50%)
|
||||||
await interaction.response.send_message("You must be in a voice channel to use this command.", ephemeral=True)
|
|
||||||
return
|
|
||||||
|
|
||||||
channel = interaction.user.voice.channel
|
|
||||||
if interaction.guild.id in voice_clients:
|
|
||||||
await interaction.response.send_message("Amber is already in a voice channel.")
|
|
||||||
else:
|
|
||||||
voice_client = await channel.connect()
|
|
||||||
voice_clients[interaction.guild.id] = voice_client
|
|
||||||
await interaction.response.send_message(f"Amber joined {channel.name}!")
|
|
||||||
|
|
||||||
|
|
||||||
async def leave_voice(interaction: discord.Interaction):
|
|
||||||
guild_id = interaction.guild.id
|
|
||||||
if guild_id not in voice_clients:
|
|
||||||
await interaction.response.send_message("Amber is not connected to a voice channel.")
|
|
||||||
return
|
|
||||||
|
|
||||||
voice_client = voice_clients[guild_id]
|
|
||||||
await voice_client.disconnect()
|
|
||||||
voice_clients.pop(guild_id, None)
|
|
||||||
await interaction.response.send_message("Amber has left the voice channel.")
|
|
||||||
|
|
||||||
|
|
||||||
async def play_audio(interaction: discord.Interaction, query: str):
|
async def play_audio(interaction: discord.Interaction, query: str):
|
||||||
guild_id = interaction.guild.id
|
guild_id = interaction.guild.id
|
||||||
|
|
||||||
if guild_id not in voice_clients:
|
if guild_id not in voice_clients:
|
||||||
await interaction.response.send_message("Amber is not connected to a voice channel.")
|
await interaction.response.send_message("Amber is not connected to a voice channel.")
|
||||||
return
|
return
|
||||||
|
|
||||||
voice_client = voice_clients[guild_id]
|
voice_client = voice_clients[guild_id]
|
||||||
|
|
||||||
if not voice_client.is_connected():
|
if not voice_client.is_connected():
|
||||||
await interaction.response.send_message("Amber is not in a voice channel.")
|
await interaction.response.send_message("Amber is not in a voice channel.")
|
||||||
return
|
return
|
||||||
|
|
||||||
await interaction.response.defer() # Indicate the bot is processing the request
|
await interaction.response.defer()
|
||||||
|
|
||||||
# yt-dlp options
|
# Search for the song on YouTube
|
||||||
ydl_opts = {
|
ydl_opts = {
|
||||||
'format': 'bestaudio/best',
|
'format': 'bestaudio/best',
|
||||||
'quiet': True,
|
'quiet': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Search for the query on YouTube
|
|
||||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||||
try:
|
try:
|
||||||
info = ydl.extract_info(f"ytsearch:{query}", download=False)['entries'][0]
|
info = ydl.extract_info(f"ytsearch:{query}", download=False)['entries'][0]
|
||||||
@ -57,14 +36,116 @@ async def play_audio(interaction: discord.Interaction, query: str):
|
|||||||
await interaction.followup.send(f"Failed to find or play the requested audio. Error: {str(e)}")
|
await interaction.followup.send(f"Failed to find or play the requested audio. Error: {str(e)}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Extract the audio URL and metadata
|
song_url = info['url']
|
||||||
url2 = info['url']
|
|
||||||
title = info.get('title', 'Unknown Title')
|
title = info.get('title', 'Unknown Title')
|
||||||
|
|
||||||
# Stop any existing audio and play the new one
|
# Add the song to the queue
|
||||||
voice_client.stop()
|
if guild_id not in music_queues:
|
||||||
|
music_queues[guild_id] = []
|
||||||
|
|
||||||
|
music_queues[guild_id].append((song_url, title))
|
||||||
|
await interaction.followup.send(f"✅ **Added to queue:** {title}")
|
||||||
|
|
||||||
|
# If nothing is playing, start playback
|
||||||
|
if not voice_client.is_playing():
|
||||||
|
await play_next(interaction)
|
||||||
|
|
||||||
|
|
||||||
|
async def play_next(interaction: discord.Interaction):
|
||||||
|
guild_id = interaction.guild.id
|
||||||
|
|
||||||
|
if guild_id not in music_queues or not music_queues[guild_id]:
|
||||||
|
await interaction.followup.send("❌ **No songs in the queue.**")
|
||||||
|
return
|
||||||
|
|
||||||
|
voice_client = voice_clients[guild_id]
|
||||||
|
song_url, title = music_queues[guild_id].pop(0)
|
||||||
|
current_tracks[guild_id] = title
|
||||||
|
|
||||||
|
# Prepare FFmpeg options
|
||||||
ffmpeg_options = {
|
ffmpeg_options = {
|
||||||
|
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
|
||||||
'options': '-vn',
|
'options': '-vn',
|
||||||
}
|
}
|
||||||
voice_client.play(discord.FFmpegPCMAudio(url2, **ffmpeg_options))
|
|
||||||
await interaction.followup.send(f"Now playing: {title}")
|
try:
|
||||||
|
source = discord.FFmpegPCMAudio(song_url, **ffmpeg_options)
|
||||||
|
volume = volumes.get(guild_id, default_volume)
|
||||||
|
source = discord.PCMVolumeTransformer(source, volume=volume)
|
||||||
|
|
||||||
|
# Play the audio
|
||||||
|
voice_client.play(
|
||||||
|
source,
|
||||||
|
after=lambda e: asyncio.run_coroutine_threadsafe(
|
||||||
|
play_next(interaction), interaction.client.loop
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await interaction.followup.send(f"🎵 **Now playing:** {title}")
|
||||||
|
except Exception as e:
|
||||||
|
await interaction.followup.send(f"Failed to play the next song. Error: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
async def stop_audio(interaction: discord.Interaction):
|
||||||
|
guild_id = interaction.guild.id
|
||||||
|
|
||||||
|
if guild_id in voice_clients:
|
||||||
|
voice_client = voice_clients[guild_id]
|
||||||
|
if voice_client.is_playing():
|
||||||
|
voice_client.stop()
|
||||||
|
music_queues[guild_id] = [] # Clear the queue
|
||||||
|
current_tracks.pop(guild_id, None) # Remove the current track
|
||||||
|
await interaction.response.send_message("🛑 **Playback stopped and queue cleared.**")
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message("❌ **No music is playing.**")
|
||||||
|
|
||||||
|
|
||||||
|
async def set_volume(interaction: discord.Interaction, level: int):
|
||||||
|
guild_id = interaction.guild.id
|
||||||
|
|
||||||
|
if level < 0 or level > 100:
|
||||||
|
await interaction.response.send_message("❌ **Volume must be between 0 and 100.**")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set the volume
|
||||||
|
volume = level / 100
|
||||||
|
volumes[guild_id] = volume
|
||||||
|
|
||||||
|
# Adjust volume for the current source if playing
|
||||||
|
if guild_id in voice_clients and voice_clients[guild_id].is_playing():
|
||||||
|
source = voice_clients[guild_id].source
|
||||||
|
if isinstance(source, discord.PCMVolumeTransformer):
|
||||||
|
source.volume = volume
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"🔊 **Volume set to {level}%**.")
|
||||||
|
|
||||||
|
|
||||||
|
async def join_voice(interaction: discord.Interaction):
|
||||||
|
if interaction.user.voice is None or interaction.user.voice.channel is None:
|
||||||
|
await interaction.response.send_message("You need to be in a voice channel for me to join.")
|
||||||
|
return
|
||||||
|
|
||||||
|
channel = interaction.user.voice.channel
|
||||||
|
guild_id = interaction.guild.id
|
||||||
|
|
||||||
|
# Connect to the voice channel
|
||||||
|
if guild_id not in voice_clients:
|
||||||
|
voice_clients[guild_id] = await channel.connect()
|
||||||
|
await interaction.response.send_message(f"✅ **Joined {channel.name}.**")
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message("❌ **I am already in a voice channel.**")
|
||||||
|
|
||||||
|
|
||||||
|
async def leave_voice(interaction: discord.Interaction):
|
||||||
|
guild_id = interaction.guild.id
|
||||||
|
|
||||||
|
if guild_id in voice_clients:
|
||||||
|
voice_client = voice_clients[guild_id]
|
||||||
|
if voice_client.is_connected():
|
||||||
|
await voice_client.disconnect()
|
||||||
|
voice_clients.pop(guild_id, None)
|
||||||
|
await interaction.response.send_message("👋 **Left the voice channel.**")
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message("❌ **I am not connected to any voice channel.**")
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message("❌ **I am not connected to any voice channel.**")
|
||||||
|
19
commands.py
19
commands.py
@ -1,20 +1,27 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from audio import join_voice, leave_voice, play_audio
|
from audio import play_audio, stop_audio, set_volume, join_voice, leave_voice
|
||||||
|
|
||||||
|
|
||||||
async def setup_commands(client):
|
async def setup_commands(client, guild_id=None):
|
||||||
@client.tree.command(name="join", description="Amber joins the voice channel you're in.")
|
@client.tree.command(name="join", description="Join the user's current voice channel.")
|
||||||
async def join(interaction: discord.Interaction):
|
async def join(interaction: discord.Interaction):
|
||||||
await join_voice(interaction)
|
await join_voice(interaction)
|
||||||
|
|
||||||
@client.tree.command(name="leave", description="Amber leaves the current voice channel.")
|
@client.tree.command(name="leave", description="Leave the current voice channel.")
|
||||||
async def leave(interaction: discord.Interaction):
|
async def leave(interaction: discord.Interaction):
|
||||||
await leave_voice(interaction)
|
await leave_voice(interaction)
|
||||||
|
|
||||||
@client.tree.command(name="play", description="Search and play a song by name or YouTube URL.")
|
@client.tree.command(name="play", description="Play a song by title or artist.")
|
||||||
@app_commands.describe(query="The name or YouTube URL of the song.")
|
|
||||||
async def play(interaction: discord.Interaction, query: str):
|
async def play(interaction: discord.Interaction, query: str):
|
||||||
await play_audio(interaction, query)
|
await play_audio(interaction, query)
|
||||||
|
|
||||||
|
@client.tree.command(name="stop", description="Stop playback and clear the queue.")
|
||||||
|
async def stop(interaction: discord.Interaction):
|
||||||
|
await stop_audio(interaction)
|
||||||
|
|
||||||
|
@client.tree.command(name="volume", description="Set playback volume.")
|
||||||
|
async def volume(interaction: discord.Interaction, level: int):
|
||||||
|
await set_volume(interaction, level)
|
||||||
|
|
||||||
await client.tree.sync()
|
await client.tree.sync()
|
||||||
|
47
main.py
47
main.py
@ -1,11 +1,23 @@
|
|||||||
import discord
|
|
||||||
from discord.ext import commands
|
|
||||||
from commands import setup_commands
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
import discord
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from commands import setup_commands
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
TOKEN = os.getenv("DISCORD_TOKEN")
|
||||||
|
GUILD_ID = os.getenv("GUILD_ID")
|
||||||
|
|
||||||
|
# Validate Guild ID
|
||||||
|
if GUILD_ID:
|
||||||
|
try:
|
||||||
|
GUILD_ID = int(GUILD_ID)
|
||||||
|
except ValueError:
|
||||||
|
logging.error("Invalid GUILD_ID in .env file. It must be a numeric value.")
|
||||||
|
GUILD_ID = None
|
||||||
|
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
intents.messages = True
|
intents.messages = True
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
@ -18,18 +30,25 @@ class AmberClient(discord.Client):
|
|||||||
super().__init__(intents=intents)
|
super().__init__(intents=intents)
|
||||||
self.tree = discord.app_commands.CommandTree(self)
|
self.tree = discord.app_commands.CommandTree(self)
|
||||||
|
|
||||||
async def setup_hook(self):
|
|
||||||
# Register commands
|
|
||||||
await setup_commands(self)
|
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
print(f"Amber is online as {self.user}")
|
logging.info(f"Amber is online as {self.user}")
|
||||||
|
|
||||||
|
# Sync commands after the bot is fully ready
|
||||||
|
if GUILD_ID:
|
||||||
|
logging.info(f"Setting up commands for guild: {GUILD_ID}")
|
||||||
|
else:
|
||||||
|
logging.info("Setting up global commands (no guild ID specified).")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await setup_commands(self, guild_id=GUILD_ID)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to setup commands: {e}")
|
||||||
|
|
||||||
|
|
||||||
# Initialize the bot
|
logging.basicConfig(level=logging.INFO)
|
||||||
client = AmberClient()
|
client = AmberClient()
|
||||||
|
|
||||||
|
if TOKEN:
|
||||||
# Run the bot
|
client.run(TOKEN)
|
||||||
TOKEN = os.getenv("DISCORD_TOKEN")
|
else:
|
||||||
client.run(TOKEN)
|
logging.error("Bot token not found. Check your .env file.")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user