From c802be1a611d407f56866b910f88f0df5a52d100 Mon Sep 17 00:00:00 2001 From: Azaaxin Date: Sun, 25 Jun 2023 11:08:14 +0200 Subject: [PATCH] Add stop functionality, fix duration --- ReAuthenticate.js | 3 - commands/loop.js | 30 +++++----- commands/pause.js | 32 ---------- commands/{pause_resume.js => pauseResume.js} | 22 +++++-- commands/play.js | 57 +++++++++--------- commands/queue.js | 33 ++++++----- commands/resume.js | 32 ---------- commands/stop.js | 30 ++++++++++ index.js | 62 +++++++++++--------- musicQueue.js | 8 +++ music_sources/soundcloud.js | 10 ++-- music_sources/spotify.js | 7 +-- music_sources/youtube.js | 45 ++++++++++---- package.json | 1 + utils/musicPlayer.js | 59 +++++++++++++------ utils/progress.js | 38 ++++++++++++ utils/registerCommands.js | 61 +++++++++++-------- 17 files changed, 304 insertions(+), 226 deletions(-) delete mode 100644 commands/pause.js rename commands/{pause_resume.js => pauseResume.js} (53%) delete mode 100644 commands/resume.js create mode 100644 commands/stop.js create mode 100644 utils/progress.js diff --git a/ReAuthenticate.js b/ReAuthenticate.js index b772b79..bda2c3a 100644 --- a/ReAuthenticate.js +++ b/ReAuthenticate.js @@ -1,9 +1,6 @@ const play = require('play-dl'); async function ReAuth() { -/*if (play.is_expired()) { - await play.refreshToken() -}*/ play.getFreeClientID().then((clientID) => { play.setToken({ diff --git a/commands/loop.js b/commands/loop.js index 262f477..ec3053a 100644 --- a/commands/loop.js +++ b/commands/loop.js @@ -1,32 +1,34 @@ -const musicQueue = require('../musicQueue'); +const musicQueue = require("../musicQueue"); async function enableLooping(interaction) { await interaction.deferReply(); const guildId = interaction.guild.id; + musicQueue.enableLooping(guildId); - interaction.followUp('Enabled looping for the current queue.'); + interaction.followUp("Enabled looping for the current queue."); } async function unloopCommand(interaction) { await interaction.deferReply(); const guildId = interaction.guild.id; + musicQueue.disableLooping(guildId); - interaction.followUp('Disabled looping for the current queue.'); + interaction.followUp("Disabled looping for the current queue."); } async function toggleLoopCommand(interaction) { - await interaction.deferReply(); - const guildId = interaction.guild.id; - if (musicQueue.looping.has(guildId) && musicQueue.looping.get(guildId)) { - musicQueue.disableLooping(guildId, false); - interaction.followUp('Disabled looping for the current queue.'); - } else { - musicQueue.enableLooping(guildId, true); - interaction.followUp('Enabled looping for the current queue.'); - } + await interaction.deferReply(); + const guildId = interaction.guild.id; + + if (musicQueue.looping.has(guildId) && musicQueue.looping.get(guildId)) { + musicQueue.disableLooping(guildId, false); + interaction.followUp("Disabled looping for the current queue."); + } else { + musicQueue.enableLooping(guildId, true); + interaction.followUp("Enabled looping for the current queue."); + } } module.exports.toggleLoopCommand = toggleLoopCommand; - module.exports.unloopCommand = unloopCommand; -module.exports.enableLooping = enableLooping; \ No newline at end of file +module.exports.enableLooping = enableLooping; diff --git a/commands/pause.js b/commands/pause.js deleted file mode 100644 index dea87ef..0000000 --- a/commands/pause.js +++ /dev/null @@ -1,32 +0,0 @@ -const { musicPlayer } = require('../utils/musicPlayer'); -const { AudioPlayerStatus, joinVoiceChannel, AudioPlayerState } = require('@discordjs/voice'); - -async function pauseCommand(interaction) { - await interaction.deferReply(); - - const voiceChannel = interaction.member.voice.channel; - - const connection = joinVoiceChannel({ - channelId: voiceChannel.id, - guildId: interaction.guild.id, - adapterCreator: interaction.guild.voiceAdapterCreator, - selfDeaf: false, - selfMute: false - }); - - let player = await musicPlayer(interaction.guild.id, connection, false); - - if (!voiceChannel) { - return interaction.followUp('You must be in a voice channel to use this command.'); - } - - if (!player) { - return interaction.followUp('I am not currently playing music in a voice channel.'); - } - -// player.pause(); - - interaction.followUp('Paused the music.'); -} - -module.exports.pauseCommand = pauseCommand; \ No newline at end of file diff --git a/commands/pause_resume.js b/commands/pauseResume.js similarity index 53% rename from commands/pause_resume.js rename to commands/pauseResume.js index 9f9c8fa..baabf41 100644 --- a/commands/pause_resume.js +++ b/commands/pauseResume.js @@ -1,24 +1,34 @@ -const { getVoiceConnection } = require('@discordjs/voice'); +const { getVoiceConnection } = require("@discordjs/voice"); async function pauseCommand(interaction) { await interaction.deferReply(); + const connection = getVoiceConnection(interaction.guild.id); + if (!connection) { - return interaction.followUp('There is no active music player in this server.'); + return interaction.followUp( + "There is no active music player in this server." + ); } + connection.state.subscription.player.pause(); - interaction.followUp('Paused the music.'); + interaction.followUp("Paused the music."); } async function unpauseCommand(interaction) { await interaction.deferReply(); + const connection = getVoiceConnection(interaction.guild.id); + if (!connection) { - return interaction.followUp('There is no active music player in this server.'); + return interaction.followUp( + "There is no active music player in this server." + ); } + connection.state.subscription.player.unpause(); - interaction.followUp('Unpaused the music.'); + interaction.followUp("Resumed the music."); } module.exports.pauseCommand = pauseCommand; -module.exports.unpauseCommand = unpauseCommand; \ No newline at end of file +module.exports.unpauseCommand = unpauseCommand; diff --git a/commands/play.js b/commands/play.js index 237348f..a65ca59 100644 --- a/commands/play.js +++ b/commands/play.js @@ -1,33 +1,32 @@ -const { getMusicStream } = require('./../utils/getMusicStream'); -const musicQueue = require('../musicQueue'); -const { musicPlayer } = require('../utils/musicPlayer'); - -const { - joinVoiceChannel, -} = require('@discordjs/voice'); +const { getMusicStream } = require("./../utils/getMusicStream"); +const musicQueue = require("../musicQueue"); +const { musicPlayer } = require("../utils/musicPlayer"); +const { joinVoiceChannel } = require("@discordjs/voice"); async function playCommand(interaction) { - await interaction.deferReply(); - - const query = interaction.options.getString('input'); - const voiceChannel = interaction.member.voice.channel; - - if (!voiceChannel) { - return interaction.followUp('You must be in a voice channel to use this command.'); - } - const song = await getMusicStream(query); - - musicQueue.addToQueue(interaction.guild.id, song); - - const connection = joinVoiceChannel({ - channelId: voiceChannel.id, - guildId: interaction.guild.id, - adapterCreator: interaction.guild.voiceAdapterCreator, - selfDeaf: false, - selfMute: false - }); - - musicPlayer(interaction.guild.id, connection, interaction); + await interaction.deferReply(); + + const query = interaction.options.getString("input"); + const voiceChannel = interaction.member.voice.channel; + + if (!voiceChannel) { + return interaction.followUp( + "You must be in a voice channel to use this command." + ); + } + const song = await getMusicStream(query); + + musicQueue.addToQueue(interaction.guild.id, song); + + const connection = joinVoiceChannel({ + channelId: voiceChannel.id, + guildId: interaction.guild.id, + adapterCreator: interaction.guild.voiceAdapterCreator, + selfDeaf: false, + selfMute: false, + }); + + musicPlayer(interaction.guild.id, connection, interaction); } -module.exports.playCommand = playCommand; \ No newline at end of file +module.exports.playCommand = playCommand; diff --git a/commands/queue.js b/commands/queue.js index b993637..feb99e1 100644 --- a/commands/queue.js +++ b/commands/queue.js @@ -1,24 +1,27 @@ -const musicQueue = require('../musicQueue'); -const { getMusicStream } = require('../utils/getMusicStream'); +const musicQueue = require("../musicQueue"); +const { getMusicStream } = require("../utils/getMusicStream"); async function queueCommand(interaction) { - await interaction.deferReply(); + await interaction.deferReply(); - const query = interaction.options.getString('song'); - const voiceChannel = interaction.member.voice.channel; + const query = interaction.options.getString("song"); + const voiceChannel = interaction.member.voice.channel; - if (!voiceChannel) { - return interaction.followUp('You must be in a voice channel to use this command.'); - } + if (!voiceChannel) { + return interaction.followUp( + "You must be in a voice channel to use this command." + ); + } - const song = await getMusicStream(query); - if (!song) { - return interaction.followUp('Error finding song. Try Again.').then(msg => setTimeout(() => msg.delete(), 10000)); - } + const song = await getMusicStream(query); + if (!song) { + return interaction + .followUp("Error finding song. Try Again.") + .then((msg) => setTimeout(() => msg.delete(), 10000)); + } - musicQueue.addToQueue(interaction.guild.id, song); - - interaction.followUp(`Added ${song.title} to the queue.`); + musicQueue.addToQueue(interaction.guild.id, song); + interaction.followUp(`Added ${song.title} to the queue.`); } module.exports.queueCommand = queueCommand; diff --git a/commands/resume.js b/commands/resume.js deleted file mode 100644 index 09d51d2..0000000 --- a/commands/resume.js +++ /dev/null @@ -1,32 +0,0 @@ -const { musicPlayer } = require('../utils/musicPlayer'); -const { joinVoiceChannel } = require('@discordjs/voice'); - -async function resumeCommand(interaction) { - await interaction.deferReply(); - - const voiceChannel = interaction.member.voice.channel; - - const connection = joinVoiceChannel({ - channelId: voiceChannel.id, - guildId: interaction.guild.id, - adapterCreator: interaction.guild.voiceAdapterCreator, - selfDeaf: false, - selfMute: false - }); - - let player = await musicPlayer(interaction.guild.id, connection, false); - - if (!voiceChannel) { - return interaction.followUp('You must be in a voice channel to use this command.'); - } - - if (!player) { - return interaction.followUp('I am not currently playing music in a voice channel.'); - } - - player.unpause(); - - interaction.followUp('Resumed the music.'); -} - -module.exports.resumeCommand = resumeCommand; \ No newline at end of file diff --git a/commands/stop.js b/commands/stop.js new file mode 100644 index 0000000..7a99251 --- /dev/null +++ b/commands/stop.js @@ -0,0 +1,30 @@ +const musicQueue = require("../musicQueue"); +const { getVoiceConnection } = require("@discordjs/voice"); + +async function stopCommand(interaction) { + await interaction.deferReply(); + + const voiceChannel = interaction.member.voice.channel; + const connection = getVoiceConnection(interaction.guild.id); + + if (!voiceChannel) { + return interaction.followUp( + "You must be in a voice channel to use this command." + ); + } + + const guildId = interaction.guild.id; + + if (!connection.state.subscription.player) { + return interaction.followUp( + "I am not currently playing music in a voice channel." + ); + } + + connection.state.subscription.player.stop(); + musicQueue.clearQueue(guildId); + + interaction.followUp("Stopped the music and cleared the queue."); +} + +module.exports.stopCommand = stopCommand; diff --git a/index.js b/index.js index 42e0f16..d7c6e97 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,8 @@ const { Client, GatewayIntentBits } = require('discord.js'); const { registerCommands } = require('./utils/registerCommands'); const { playCommand } = require('./commands/play'); const { queueCommand } = require('./commands/queue'); -const { pauseCommand, unpauseCommand } = require('./commands/pause_resume'); +const { stopCommand } = require('./commands/stop'); +const { pauseCommand, unpauseCommand } = require('./commands/pauseResume'); const { toggleLoopCommand } = require('./commands/loop'); const { ReAuth } = require('./ReAuthenticate'); @@ -11,13 +12,14 @@ const clientId = process.parsed.clientId; const token = process.parsed.token; const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildVoiceStates, - GatewayIntentBits.GuildIntegrations - ] }) + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.GuildIntegrations + ] +}) client.on('ready', async () => { console.log(`Logged in as ${client.user.tag}!`); @@ -26,27 +28,29 @@ client.on('ready', async () => { }); client.on('interactionCreate', async (interaction) => { - if (!interaction.isCommand()) return; + if (!interaction.isCommand()) return; + + const { commandName } = interaction; + + if (commandName === 'play') { + await playCommand(interaction); + } else if (commandName === 'queue') { + await queueCommand(interaction); + } else if (commandName === 'pause') { + await pauseCommand(interaction); + } else if (commandName === 'resume') { + await unpauseCommand(interaction); + } else if (commandName === 'loop') { + await toggleLoopCommand(interaction); + } else if (commandName === 'stop') { + await stopCommand(interaction); + } +}); - const { commandName } = interaction; - - if (commandName === 'play') { - await playCommand(interaction); - } else if (commandName === 'queue') { - await queueCommand(interaction); - } else if (commandName === 'pause') { - await pauseCommand(interaction); - } else if (commandName === 'resume') { - await unpauseCommand(interaction); - } else if (commandName === 'loop') { - await toggleLoopCommand(interaction); - } - }); - - client.on('messageCreate', async (message) => { - if(message.content == 'reauth') { - await ReAuth(); - } - }); +client.on('messageCreate', async (message) => { + if(message.content == 'reauth') { + await ReAuth(); + } +}); client.login(token); \ No newline at end of file diff --git a/musicQueue.js b/musicQueue.js index 8b0821c..a1fbbc8 100644 --- a/musicQueue.js +++ b/musicQueue.js @@ -45,6 +45,14 @@ class MusicQueue { disableLooping(guildId) { this.looping.set(guildId, false); } + + clearQueue(guildId) { + if (!this.queue.has(guildId)) { + return; + } + + this.queue.set(guildId, []); + } } module.exports = new MusicQueue(); \ No newline at end of file diff --git a/music_sources/soundcloud.js b/music_sources/soundcloud.js index 561c43f..ab44b6f 100644 --- a/music_sources/soundcloud.js +++ b/music_sources/soundcloud.js @@ -1,14 +1,14 @@ -const playdl = require('play-dl'); +const playdl = require("play-dl"); async function getStream(query) { - let songInformation = await playdl.soundcloud(query) // Make sure that url is track url only. For playlist, make some logic. + let songInformation = await playdl.soundcloud(query); let stream = await playdl.stream_from_info(songInformation, { quality: 2 }); return { title: songInformation.name, stream: stream.stream, - duration: songInformation.durationInSec / 1000, - userInput: query - } + duration: songInformation.durationInSec * 1000, + userInput: query, + }; } module.exports.getStream = getStream; \ No newline at end of file diff --git a/music_sources/spotify.js b/music_sources/spotify.js index e6f6aac..5a7871a 100644 --- a/music_sources/spotify.js +++ b/music_sources/spotify.js @@ -1,14 +1,13 @@ const playdl = require('play-dl'); - +//TODO ADD SPOTIFY SUPPORT async function getStream(query) { const trackInfo = await playdl.spotify(query); let searched = await play.search(`${trackInfo.name}`, { limit: 1 - }) // This will search the found track on youtube. - - let stream = await play.stream(searched[0].url) // This will create stream from the above search + }) + let stream = await play.stream(searched[0].url) return stream; } diff --git a/music_sources/youtube.js b/music_sources/youtube.js index 56e25fd..d92b38a 100644 --- a/music_sources/youtube.js +++ b/music_sources/youtube.js @@ -1,5 +1,5 @@ -const ytsr = require('ytsr'); -const playdl = require('play-dl'); +const ytsr = require("ytsr"); +const playdl = require("play-dl"); async function getStream(query) { try { @@ -7,29 +7,48 @@ async function getStream(query) { const match = query.match(regex); let videoId; let usingYtsr = false; - if(match == null) { - let result = await playdl.search(query, { limit: 1}); + if (match == null) { + let result = await playdl.search(query, { limit: 1 }); videoId = result[0].id; if (videoId == null) { usingYtsr = true; - const searchResults = await ytsr(query, { page: 1, type: 'video' }); + const searchResults = await ytsr(query, { + page: 1, + type: "video", + }); videoId = searchResults.items[0].id; } } else { videoId = match[1]; } - const streamResult = await playdl.stream(`https://www.youtube.com/watch?v=${videoId}`, { quality: 2 }); - const infoResult = usingYtsr ? await ytsr(`https://www.youtube.com/watch?v=${videoId}`, { limit: 1}) : await playdl.video_info(`https://www.youtube.com/watch?v=${videoId}`); - console.log(infoResult) - console.log("\x1b[36m",' Id: ', videoId, 'Alternative search:', usingYtsr) + const streamResult = await playdl.stream( + `https://www.youtube.com/watch?v=${videoId}`, + { quality: 2 } + ); + const infoResult = usingYtsr + ? await ytsr(`https://www.youtube.com/watch?v=${videoId}`, { + limit: 1, + }) + : await playdl.video_info( + `https://www.youtube.com/watch?v=${videoId}` + ); + console.log("\x1b[36m"," Id: ", videoId, "Alternative search:", usingYtsr); return { - title: (usingYtsr ? infoResult.items[0].title : infoResult.video_details.title) ?? 'Unknown, error fetching title.', - duration: (usingYtsr ? infoResult.items[0].duration : infoResult.video_details.durationInSec) ?? 'Unknown, error fetching duration.', + title: + (usingYtsr + ? infoResult.items[0].title + : infoResult.video_details.title) ?? + 0, + duration: + (usingYtsr + ? infoResult.items[0].duration + : (infoResult.video_details.durationInSec * 1000)) ?? + 0, stream: streamResult.stream, type: streamResult.type, - userInput: query + userInput: query, }; } catch (error) { console.log("\x1b[31m", error); @@ -37,4 +56,4 @@ async function getStream(query) { } } -module.exports.getStream = getStream; \ No newline at end of file +module.exports.getStream = getStream; diff --git a/package.json b/package.json index 36cd27c..e79ab75 100644 --- a/package.json +++ b/package.json @@ -35,3 +35,4 @@ "ytsr": "^3.8.2" } } + diff --git a/utils/musicPlayer.js b/utils/musicPlayer.js index 032130f..fd9d3ec 100644 --- a/utils/musicPlayer.js +++ b/utils/musicPlayer.js @@ -1,22 +1,25 @@ -const { - createAudioResource, - createAudioPlayer, +const { + createAudioResource, + createAudioPlayer, NoSubscriberBehavior, AudioPlayerStatus, } = require('@discordjs/voice'); + +const { EmbedBuilder } = require('discord.js'); const musicQueue = require('../musicQueue'); - +const { progressBar } = require('../utils/progress'); + async function musicPlayer(guildId, connection, interaction) { const serverQueue = musicQueue.getQueue(guildId); - + if (serverQueue.length === 0) { - connection.destroy(); - return; + connection.destroy(); + return; } - + const song = serverQueue[0]; - - if(song.stream == null){ + + if (song.stream == null) { musicQueue.removeFromQueue(guildId); musicPlayer(guildId, connection); return; @@ -25,7 +28,7 @@ async function musicPlayer(guildId, connection, interaction) { let resource = createAudioResource(song.stream, { inputType: song.type }) - + let player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play @@ -33,16 +36,36 @@ async function musicPlayer(guildId, connection, interaction) { }) player.play(resource) - + connection.subscribe(player) - interaction.followUp(`Added **${song.title}** to the queue.`).then(message => - setTimeout(() => - message.delete(), - song.duration + 10000)); + + progressBar(0, 0, true) + + if(interaction.commandName == "play") { + interaction.followUp(`~🎵~`).then(message => { + const embed = new EmbedBuilder() + .setColor("#E0B0FF") + .setTitle("Now playing: " + song.title) + .setDescription(progressBar(song.duration, 10).progressBarString); + + message.edit({ embeds: [embed] }); + + inter = setInterval(() => { + const { progressBarString, isDone } = progressBar(song.duration, 10); + if (isDone) { + clearInterval(inter); + message.delete(); + } + embed.setDescription(progressBarString); + message.edit({ embeds: [embed] }); + }, 2000) + }); + } player.on(AudioPlayerStatus.Idle, async () => { - console.log('Song ended:', song.title); - await musicQueue.removeFromQueue(guildId) + console.log('Song ended:', song.title); + await musicQueue.removeFromQueue(guildId) + musicPlayer(guildId, connection, interaction); }); return player; diff --git a/utils/progress.js b/utils/progress.js new file mode 100644 index 0000000..67ba2ee --- /dev/null +++ b/utils/progress.js @@ -0,0 +1,38 @@ +let startTime; +let current = 0; +let percentage; + +const progressBar = (totalInMilliseconds, size, reset = false) => { + if (reset) { + startTime = Date.now(); + current = 0; + } + + if (!startTime) { + startTime = Date.now(); + } + + current = Date.now() - startTime; + + const totalInSeconds = totalInMilliseconds / 1000; + percentage = Math.min((current / 1000) / totalInSeconds, 1); + const progress = Math.round((size * percentage)); + const emptyProgress = size - progress; + + const progressText = '▇'.repeat(progress); + const emptyProgressText = '—'.repeat(emptyProgress); + const percentageText = Math.round(percentage * 100) + '%'; + + let elapsedTimeText = new Date(current).toISOString().slice(11, -5); + let totalTimeText = new Date(totalInMilliseconds).toISOString().slice(11, -5); + + if (totalTimeText.startsWith('00:')) { + elapsedTimeText = elapsedTimeText.slice(3); + totalTimeText = totalTimeText.slice(3); + } + + const progressBarString = elapsedTimeText + ' [' + progressText + emptyProgressText + ']' + percentageText + ' ' + totalTimeText; // Creating and returning the bar + + return { progressBarString, isDone: percentage === 1 }; +} +module.exports.progressBar = progressBar; diff --git a/utils/registerCommands.js b/utils/registerCommands.js index cb5527b..c37327e 100644 --- a/utils/registerCommands.js +++ b/utils/registerCommands.js @@ -1,47 +1,56 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { REST } = require('@discordjs/rest'); -const { Routes } = require('discord-api-types/v9'); +const { SlashCommandBuilder } = require("@discordjs/builders"); +const { REST } = require("@discordjs/rest"); +const { Routes } = require("discord-api-types/v9"); async function registerCommands(clientId, token) { const commands = [ new SlashCommandBuilder() - .setName('play') - .setDescription('Plays songs!') - .addStringOption(option => - option.setName('input') - .setDescription('Play song from YouTube, Spotify, SoundCloud, etc.') + .setName("play") + .setDescription("Plays songs!") + .addStringOption((option) => + option + .setName("input") + .setDescription("Play song from YouTube, Spotify, SoundCloud, etc.") .setRequired(true) ), new SlashCommandBuilder() - .setName('queue') - .setDescription('Adds a song to the queue!') - .addStringOption(option => - option.setName('song') - .setDescription('Add song from YouTube, Spotify, SoundCloud, etc. to the queue') + .setName("queue") + .setDescription("Adds a song to the queue!") + .addStringOption((option) => + option + .setName("song") + .setDescription( + "Add song from YouTube, Spotify, SoundCloud, etc. to the queue" + ) .setRequired(true) ), new SlashCommandBuilder() - .setName('pause') - .setDescription('Pauses the current song!'), + .setName("pause") + .setDescription("Pauses the current song!"), new SlashCommandBuilder() - .setName('resume') - .setDescription('Resumes the current song!'), + .setName("resume") + .setDescription("Resumes the current song!"), new SlashCommandBuilder() - .setName('loop') - .setDescription('Loops the current song! (toggle)'), + .setName("loop") + .setDescription("Loops the current song! (toggle)"), + new SlashCommandBuilder() + .setName("stop") + .setDescription("Stops the current song!"), ]; - const rest = new REST({ version: '9' }).setToken(token); + const rest = new REST({ + version: "9", + }) + .setToken(token); try { - console.log('Started refreshing application (/) commands.'); + console.log("\x1b[35m", "Started refreshing application (/) commands."); - await rest.put( - Routes.applicationCommands(clientId), - { body: commands }, - ); + await rest.put(Routes.applicationCommands(clientId), { + body: commands, + }); - console.log('Successfully reloaded application (/) commands.'); + console.log("\x1b[35m", "Successfully reloaded application (/) commands."); } catch (error) { console.error(error); }