2025-05-24 02:12:40 +07:00

153 lines
5.6 KiB
JavaScript

const {createAudioPlayer, createAudioResource, joinVoiceChannel, getVoiceConnection} = require("@discordjs/voice")
const {dir} = require("../index")
const { AudioPlayerStatus } = require("@discordjs/voice")
const YTDlpWrap = require("yt-dlp-wrap").default
const ytDlp = new YTDlpWrap(`${dir}/yt-dlp`)
const players = {}
module.exports.commands = [
{
name: "play",
description: "Joins your VC and plays music by youtube link.",
arguments: ["link", false], // If it's not an OBJECT type, you provide it like that lol.
run: async (ctx, link, loop) => {
// Getting the guild member to get their voice client
const author = ctx.author
const member = await ctx.guild.members.fetch(author)
// Initiating the channel variable (undefined)
let channel;
// Checking if the member is in a voice chat
if (member.voice) {
channel = member.voice.channel
}
// Returns if the user is not in vc or the bot is already in one
if (!channel) {
return ctx.reply("You are not in a VC right now.")
} else if (ctx.guild.members.me.voice.channel && ctx.guild.members.me.voice.channel.id !== channel.id) {
return ctx.reply("Already in a vc.")
}
let connection;
// Checking if the bot is already in the vc
if (!ctx.guild.members.me.voice.channel) {
// Connecting to the voice channel
connection = joinVoiceChannel({
channelId: channel.id, // Jetbrains is very angry over this for no reason?
guildId: channel.guild.id, // Or maybe this, it shows String instead of Snowflake.
adapterCreator: channel.guild.voiceAdapterCreator,
})
} else {
// Getting an existing connection
connection = getVoiceConnection(ctx.guild.id)
}
const reply = await ctx.reply("Loading music data.")
// Running yt-dlp (getting music title)
const metadata = await ytDlp.getVideoInfo(link);
await reply.edit(`Downloading ${metadata.title}`)
// Running yt-dlp (downloading music)
ytDlp.exec([
// Arguments to run yt-dlp with
link,
'-f',
'best',
'-o',
`${dir}/music/${metadata.title}.mp3`,
'--extract-audio',
'--audio-format',
'mp3'
]).on('close', () => {
reply.edit(`Playing ${metadata.title}`)
// Stopping old audio player
if (players[ctx.guild.id]) {
players[ctx.guild.id].stop()
}
// Checking if the bot is still in the VC and if it's the same VC.
if (!ctx.guild.members.me.voice || (ctx.guild.members.me.voice && !ctx.guild.members.me.voice.channel)||
(ctx.guild.members.me.voice && ctx.guild.members.me.voice.channel &&
ctx.guild.members.me.voice.channel.id !== channel.id)) {
return reply.edit("Not in a VC anymore, not playing.")
}
// Connecting audio player
const player = createAudioPlayer()
// Setting the global player to this
players[ctx.guild.id] = player
const resource = createAudioResource(`${dir}/music/${metadata.title}.mp3`)
// Playing the music with the player
player.play(resource)
// Subscribing the connection to the player
connection.subscribe(player)
// Make it play again and again if it's looping
if (loop) {
player.on("stateChange", (oldState, newState) => {
if (newState.status === AudioPlayerStatus.Idle && players[ctx.guild.id] !== undefined) {
// We have to create a new resource every time
const resource = createAudioResource(`${dir}/music/${metadata.title}.mp3`)
// Playing the music with the player
player.play(resource)
}
})
}
})
}
},
{
name: "stop",
description: "Stop music",
run: (ctx) => {
const voice = ctx.guild.members.me.voice
// Checking if bot is in a voice channel
if (!voice || !players[ctx.guild.id]) {
return ctx.reply("Not in a voice channel.")
}
// Stopping the player
players[ctx.guild.id].stop()
// Removing the player (needed on line 100 check)
players[ctx.guild.id] = undefined
}
},
{
name: "leave",
description: "Leave the channel",
run: async (ctx) => {
const voice = ctx.guild.members.me.voice
// Checking if bot is in a voice channel
if (!voice || !players[ctx.guild.id]) {
return ctx.reply("Not in a voice channel.")
}
// Stopping the player
players[ctx.guild.id].stop()
// Removing the player (needed on line 100 check)
players[ctx.guild.id] = undefined
// Disconnecting, obviously.
await voice.disconnect()
}
}
]
module.exports.players = players // For use in events/voice.js