2024-07-20 18:45:02 -04:00
|
|
|
import discord
|
|
|
|
from discord.ext import commands
|
|
|
|
from discord import app_commands
|
|
|
|
from yt_dlp import YoutubeDL
|
|
|
|
import os
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
load_dotenv()
|
|
|
|
|
|
|
|
YTDL_OPTIONS = {
|
|
|
|
'format': 'bestaudio',
|
|
|
|
'noplaylist': 'True',
|
|
|
|
}
|
|
|
|
|
|
|
|
FFMPEG_OPTIONS = {
|
|
|
|
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
|
|
|
|
'options': '-vn'
|
|
|
|
}
|
|
|
|
|
|
|
|
ytdl = YoutubeDL(YTDL_OPTIONS)
|
|
|
|
|
2024-08-14 14:05:20 -04:00
|
|
|
|
2024-07-20 18:45:02 -04:00
|
|
|
class Music(commands.Cog):
|
|
|
|
def __init__(self, bot):
|
|
|
|
self.bot = bot
|
|
|
|
self.queue = []
|
|
|
|
self.is_playing = False
|
|
|
|
self.volume = 0.3
|
2024-08-14 13:52:20 -04:00
|
|
|
self.loop = False # Initialize loop state
|
|
|
|
self.current_song = None # Track the current song
|
2024-07-20 18:45:02 -04:00
|
|
|
|
|
|
|
async def join(self, interaction: discord.Interaction):
|
|
|
|
channel = interaction.user.voice.channel
|
|
|
|
if interaction.guild.voice_client is None:
|
|
|
|
await channel.connect(self_deaf=True) # Join the channel deafened
|
|
|
|
await interaction.followup.send("Joined the voice channel.")
|
|
|
|
else:
|
|
|
|
await interaction.followup.send("Already in a voice channel.")
|
|
|
|
|
|
|
|
async def leave(self, interaction: discord.Interaction):
|
|
|
|
if interaction.guild.voice_client:
|
|
|
|
await interaction.guild.voice_client.disconnect()
|
|
|
|
await interaction.followup.send("Left the voice channel.")
|
|
|
|
else:
|
|
|
|
await interaction.followup.send("Not connected to a voice channel.")
|
|
|
|
|
|
|
|
async def play(self, interaction: discord.Interaction, search: str):
|
|
|
|
if not interaction.guild.voice_client:
|
|
|
|
await self.join(interaction)
|
|
|
|
|
|
|
|
info = ytdl.extract_info(f"ytsearch:{search}", download=False)['entries'][0]
|
|
|
|
url = info['url']
|
|
|
|
|
|
|
|
if interaction.guild.voice_client.is_playing():
|
|
|
|
self.queue.append((url, info['title']))
|
|
|
|
await interaction.followup.send(f'Queued: {info["title"]}')
|
|
|
|
else:
|
2024-08-14 13:52:20 -04:00
|
|
|
self.current_song = (url, info['title'])
|
2024-07-20 18:45:02 -04:00
|
|
|
source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(url, **FFMPEG_OPTIONS), volume=self.volume)
|
|
|
|
interaction.guild.voice_client.play(source, after=lambda e: self.bot.loop.create_task(self.play_next(interaction)))
|
|
|
|
self.is_playing = True
|
|
|
|
await interaction.followup.send(f'Playing: {info["title"]}')
|
|
|
|
|
|
|
|
async def play_next(self, interaction: discord.Interaction):
|
2024-08-14 13:52:20 -04:00
|
|
|
if self.loop and self.current_song: # If loop is active, repeat the current song
|
|
|
|
url, title = self.current_song
|
|
|
|
source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(url, **FFMPEG_OPTIONS), volume=self.volume)
|
|
|
|
interaction.guild.voice_client.play(source, after=lambda e: self.bot.loop.create_task(self.play_next(interaction)))
|
|
|
|
await interaction.followup.send(f'Repeating: {title}')
|
|
|
|
elif self.queue:
|
2024-07-20 18:45:02 -04:00
|
|
|
url, title = self.queue.pop(0)
|
2024-08-14 13:52:20 -04:00
|
|
|
self.current_song = (url, title)
|
2024-07-20 18:45:02 -04:00
|
|
|
source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(url, **FFMPEG_OPTIONS), volume=self.volume)
|
|
|
|
interaction.guild.voice_client.play(source, after=lambda e: self.bot.loop.create_task(self.play_next(interaction)))
|
|
|
|
await interaction.followup.send(f'Playing next: {title}')
|
|
|
|
else:
|
|
|
|
self.is_playing = False
|
|
|
|
|
|
|
|
async def pause(self, interaction: discord.Interaction):
|
|
|
|
if interaction.guild.voice_client.is_playing():
|
|
|
|
interaction.guild.voice_client.pause()
|
|
|
|
await interaction.followup.send("Paused the song.")
|
|
|
|
else:
|
|
|
|
await interaction.followup.send("No song is currently playing.")
|
|
|
|
|
|
|
|
async def resume(self, interaction: discord.Interaction):
|
|
|
|
if interaction.guild.voice_client.is_paused():
|
|
|
|
interaction.guild.voice_client.resume()
|
|
|
|
await interaction.followup.send("Resumed the song.")
|
|
|
|
else:
|
|
|
|
await interaction.followup.send("The song is not paused.")
|
|
|
|
|
|
|
|
async def stop(self, interaction: discord.Interaction):
|
|
|
|
if interaction.guild.voice_client.is_playing():
|
|
|
|
interaction.guild.voice_client.stop()
|
|
|
|
self.queue = []
|
2024-08-14 13:52:20 -04:00
|
|
|
self.current_song = None
|
2024-07-20 18:45:02 -04:00
|
|
|
await interaction.followup.send("Stopped the song.")
|
|
|
|
else:
|
|
|
|
await interaction.followup.send("No song is currently playing.")
|
|
|
|
|
|
|
|
async def set_volume(self, interaction: discord.Interaction, volume: float):
|
|
|
|
self.volume = volume
|
|
|
|
if interaction.guild.voice_client and interaction.guild.voice_client.source:
|
|
|
|
interaction.guild.voice_client.source.volume = self.volume
|
|
|
|
await interaction.followup.send(f"Volume set to {volume * 100}%.")
|
|
|
|
else:
|
|
|
|
await interaction.followup.send("No audio source found.")
|
|
|
|
|
2024-08-14 13:52:20 -04:00
|
|
|
async def toggle_loop(self, interaction: discord.Interaction):
|
|
|
|
self.loop = not self.loop # Toggle the loop state
|
|
|
|
state = "enabled" if self.loop else "disabled"
|
|
|
|
await interaction.followup.send(f"Loop has been {state}.")
|
|
|
|
|
2024-07-20 18:45:02 -04:00
|
|
|
def setup(self, tree: discord.app_commands.CommandTree):
|
|
|
|
@tree.command(name="join", description="Join the voice channel")
|
|
|
|
async def join_command(interaction: discord.Interaction):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.join(interaction)
|
|
|
|
|
|
|
|
@tree.command(name="leave", description="Leave the voice channel")
|
|
|
|
async def leave_command(interaction: discord.Interaction):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.leave(interaction)
|
|
|
|
|
|
|
|
@tree.command(name="play", description="Play a song from YouTube")
|
|
|
|
async def play_command(interaction: discord.Interaction, search: str):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.play(interaction, search)
|
|
|
|
|
|
|
|
@tree.command(name="pause", description="Pause the current song")
|
|
|
|
async def pause_command(interaction: discord.Interaction):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.pause(interaction)
|
|
|
|
|
|
|
|
@tree.command(name="resume", description="Resume the paused song")
|
|
|
|
async def resume_command(interaction: discord.Interaction):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.resume(interaction)
|
|
|
|
|
|
|
|
@tree.command(name="stop", description="Stop the current song")
|
|
|
|
async def stop_command(interaction: discord.Interaction):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.stop(interaction)
|
|
|
|
|
|
|
|
@tree.command(name="volume", description="Set the volume (0 to 1)")
|
|
|
|
async def volume_command(interaction: discord.Interaction, volume: float):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.set_volume(interaction, volume)
|
|
|
|
|
2024-08-14 13:52:20 -04:00
|
|
|
@tree.command(name="loop", description="Toggle loop for the current song")
|
|
|
|
async def loop_command(interaction: discord.Interaction):
|
|
|
|
await interaction.response.defer()
|
|
|
|
await self.toggle_loop(interaction)
|
|
|
|
|
2024-08-14 14:05:20 -04:00
|
|
|
if not tree.get_command("play"):
|
|
|
|
tree.add_command(play_command)
|
|
|
|
|
|
|
|
if not tree.get_command("pause"):
|
|
|
|
tree.add_command(pause_command)
|
|
|
|
|
|
|
|
if not tree.get_command("resume"):
|
|
|
|
tree.add_command(resume_command)
|
|
|
|
|
|
|
|
if not tree.get_command("stop"):
|
|
|
|
tree.add_command(stop_command)
|
|
|
|
|
|
|
|
if not tree.get_command("volume"):
|
|
|
|
tree.add_command(volume_command)
|
|
|
|
|
|
|
|
if not tree.get_command("loop"):
|
|
|
|
tree.add_command(loop_command)
|
|
|
|
|
|
|
|
if not tree.get_command("join"):
|
|
|
|
tree.add_command(join_command)
|
|
|
|
|
|
|
|
if not tree.get_command("leave"):
|
|
|
|
tree.add_command(leave_command)
|
|
|
|
|
2024-07-20 18:45:02 -04:00
|
|
|
|
|
|
|
def setup(bot):
|
|
|
|
music = Music(bot)
|
|
|
|
music.setup(bot.tree)
|