mirror of
https://github.com/MinazukiAmane/Tinasha-Bot.git
synced 2025-03-15 07:35:57 +08:00
music wrapper change
• Changed music wrapper lavaclient to lavalink-client • Added lavalink v4 support • Added custom player events • Added autoplay feature.
This commit is contained in:
parent
bd020a8e71
commit
03705ad4e8
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
node_modules
|
||||
docs
|
||||
.env.asli
|
||||
config.js
|
||||
|
||||
# Logs
|
||||
logs
|
||||
|
137
config.js.example
Normal file
137
config.js.example
Normal file
@ -0,0 +1,137 @@
|
||||
module.exports = {
|
||||
OWNER_IDS: [""], // Bot owner ID's
|
||||
SUPPORT_SERVER: "", // Your bot support server
|
||||
PREFIX_COMMANDS: {
|
||||
ENABLED: true, // Enable/Disable prefix commands
|
||||
DEFAULT_PREFIX: "kt?", // Default prefix for the bot
|
||||
},
|
||||
INTERACTIONS: {
|
||||
SLASH: true, // Should the interactions be enabled
|
||||
CONTEXT: true, // Should contexts be enabled
|
||||
GLOBAL: true, // Should the interactions be registered globally
|
||||
TEST_GUILD_ID: "", // Guild ID where the interactions should be registered. [** Test you commands here first **]
|
||||
},
|
||||
EMBED_COLORS: {
|
||||
BOT_EMBED: "#068ADD",
|
||||
TRANSPARENT: "#36393F",
|
||||
SUCCESS: "#00A56A",
|
||||
ERROR: "#D61A3C",
|
||||
WARNING: "#F7E919",
|
||||
},
|
||||
CACHE_SIZE: {
|
||||
GUILDS: 10000,
|
||||
USERS: 1000000,
|
||||
MEMBERS: 1000000,
|
||||
},
|
||||
MESSAGES: {
|
||||
API_ERROR: "Unexpected Backend Error! Try again later or contact support server",
|
||||
},
|
||||
|
||||
// PLUGINS
|
||||
|
||||
AUTOMOD: {
|
||||
ENABLED: true,
|
||||
LOG_EMBED: "#36393F",
|
||||
DM_EMBED: "#36393F",
|
||||
},
|
||||
|
||||
DASHBOARD: {
|
||||
enabled: true, // enable or disable dashboard
|
||||
baseURL: "http://localhost:8080", // base url
|
||||
failureURL: "http://localhost:8080", // failure redirect url
|
||||
port: "8080", // port to run the bot on
|
||||
},
|
||||
|
||||
ECONOMY: {
|
||||
ENABLED: true,
|
||||
CURRENCY: "₪",
|
||||
DAILY_COINS: 1000, // coins to be received by daily command
|
||||
MIN_BEG_AMOUNT: 1000, // minimum coins to be received when beg command is used
|
||||
MAX_BEG_AMOUNT: 25000, // maximum coins to be received when beg command is used
|
||||
},
|
||||
|
||||
MUSIC: {
|
||||
ENABLED: true,
|
||||
IDLE_TIME: 120, // Time in seconds before the bot disconnects from an idle voice channel
|
||||
DEFAULT_VOLUME: 60, // Default player volume 1-100
|
||||
MAX_SEARCH_RESULTS: 100,
|
||||
DEFAULT_SOURCE: "ytsearch", // ytsearch = Youtube, ytmsearch = Youtube Music, scsearch = SoundCloud, spsearch = Spotify
|
||||
// Add any number of lavalink nodes here
|
||||
// Refer to https://github.com/lavalink-devs/Lavalink to host your own lavalink server
|
||||
LAVALINK_NODES: [
|
||||
{
|
||||
id: "Local Node",
|
||||
host: "localhost",
|
||||
port: 2333,
|
||||
authorization: "youshallnotpass",
|
||||
secure: false,
|
||||
retryAmount: 20, // Number of reconnection attempts
|
||||
retryDelay: 30000 // Delay (in ms) between reconnection attempts
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
GIVEAWAYS: {
|
||||
ENABLED: true,
|
||||
REACTION: "🎁",
|
||||
START_EMBED: "#FF468A",
|
||||
END_EMBED: "#FF468A",
|
||||
},
|
||||
|
||||
IMAGE: {
|
||||
ENABLED: true,
|
||||
BASE_API: "https://strangeapi.hostz.me/api",
|
||||
},
|
||||
|
||||
INVITE: {
|
||||
ENABLED: true,
|
||||
},
|
||||
|
||||
MODERATION: {
|
||||
ENABLED: true,
|
||||
EMBED_COLORS: {
|
||||
TIMEOUT: "#102027",
|
||||
UNTIMEOUT: "#4B636E",
|
||||
KICK: "#FF7961",
|
||||
SOFTBAN: "#AF4448",
|
||||
BAN: "#D32F2F",
|
||||
UNBAN: "#00C853",
|
||||
VMUTE: "#102027",
|
||||
VUNMUTE: "#4B636E",
|
||||
DEAFEN: "#102027",
|
||||
UNDEAFEN: "#4B636E",
|
||||
DISCONNECT: "RANDOM",
|
||||
MOVE: "RANDOM",
|
||||
},
|
||||
},
|
||||
|
||||
PRESENCE: {
|
||||
ENABLED: true, // Whether or not the bot should update its status
|
||||
STATUS: "online", // The bot's status [online, idle, dnd, invisible]
|
||||
TYPE: "LISTENING", // Status type for the bot [ CUSTOM | PLAYING | LISTENING | WATCHING | COMPETING ]
|
||||
MESSAGE: "/play with {members} members in {servers} servers", // Your bot status message (note: in custom status type you won't have "Playing", "Listening", "Competing" prefix)
|
||||
},
|
||||
|
||||
STATS: {
|
||||
ENABLED: true,
|
||||
XP_COOLDOWN: 5, // Cooldown in seconds between messages
|
||||
DEFAULT_LVL_UP_MSG: "{member:tag}, You just advanced to **Level {level}**",
|
||||
},
|
||||
|
||||
SUGGESTIONS: {
|
||||
ENABLED: true, // Should the suggestion system be enabled
|
||||
EMOJI: {
|
||||
UP_VOTE: "⬆️",
|
||||
DOWN_VOTE: "⬇️",
|
||||
},
|
||||
DEFAULT_EMBED: "#4F545C",
|
||||
APPROVED_EMBED: "#43B581",
|
||||
DENIED_EMBED: "#F04747",
|
||||
},
|
||||
|
||||
TICKET: {
|
||||
ENABLED: true,
|
||||
CREATE_EMBED: "#068ADD",
|
||||
CLOSE_EMBED: "#068ADD",
|
||||
},
|
||||
};
|
69
package-lock.json
generated
69
package-lock.json
generated
@ -1,18 +1,16 @@
|
||||
{
|
||||
"name": "TinashaBot",
|
||||
"version": "5.6.2",
|
||||
"version": "5.7.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "TinashaBot",
|
||||
"version": "5.6.0",
|
||||
"version": "5.6.2",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@google/generative-ai": "^0.14.0",
|
||||
"@lavaclient/plugin-queue": "^0.0.1",
|
||||
"@lavaclient/queue": "^2.1.1",
|
||||
"@lavaclient/spotify": "^3.1.0",
|
||||
"@lavaclient/types": "^2.1.1",
|
||||
"@vitalets/google-translate-api": "^9.2.0",
|
||||
"common-tags": "^1.8.2",
|
||||
@ -28,7 +26,7 @@
|
||||
"express-session": "^1.18.0",
|
||||
"fixedsize-map": "^1.0.1",
|
||||
"iso-639-1": "^3.1.0",
|
||||
"lavaclient": "^5.0.0-rc.3",
|
||||
"lavalink-client": "^2.4.0",
|
||||
"module-alias": "^2.2.3",
|
||||
"moment": "^2.30.1",
|
||||
"mongoose": "^8.1.1",
|
||||
@ -192,13 +190,15 @@
|
||||
"version": "0.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@effect/data/-/data-0.17.6.tgz",
|
||||
"integrity": "sha512-/vwz7Jh05eS0qY8kczR/YyJd18d0C+PMtUkAealh4f6gwvhABLGCnktNJTcq/+UHxY0Cbv18r5uaJ4+7PPC+WQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@effect/schema": {
|
||||
"version": "0.49.4",
|
||||
"resolved": "https://registry.npmjs.org/@effect/schema/-/schema-0.49.4.tgz",
|
||||
"integrity": "sha512-Em5qFV7kXfHpt6n89B2Zwd0ccGgfFpZbBAfQuGPdw/zY18k01Tl3ufKfBA6fFphKQiWrU6JS9btTlq1+/WRRIg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"effect": "2.0.0-next.56",
|
||||
"fast-check": "^3.13.2"
|
||||
@ -343,30 +343,6 @@
|
||||
"lavalink-protocol": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@lavaclient/queue": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@lavaclient/queue/-/queue-2.1.1.tgz",
|
||||
"integrity": "sha512-2I+T+4xpb6I4xh4GjCCY/F2zazoHw/RectbKWlBZYSEMGoIGbHfOu81yi4fModigSVG0+4br8NnwHLiQX+XNcg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@lavaclient/spotify": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@lavaclient/spotify/-/spotify-3.1.0.tgz",
|
||||
"integrity": "sha512-B9AwZVyxScjJnJWJa4zMylF2i2/UOvDKL7lHWMxcezBMvOqjM+rZMr4ZTJj179qdpOaQ7zc8mBfRYSXGWJIWmA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@lavaclient/types": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@lavaclient/types/-/types-2.1.1.tgz",
|
||||
@ -2469,6 +2445,7 @@
|
||||
"resolved": "https://registry.npmjs.org/lavaclient/-/lavaclient-5.0.0-rc.3.tgz",
|
||||
"integrity": "sha512-zSB0wK9SEhXwWd918ije4UjjqMeDlP7Nry8mo5UFvQlD2YMFKxJJuKTJKc9VwgBhBjRVB0cCujAlru7NsTRdDg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@effect/schema": "^0.49.4",
|
||||
"lavalink-api-client": "1.0.1",
|
||||
@ -2486,6 +2463,7 @@
|
||||
"resolved": "https://registry.npmjs.org/lavalink-api-client/-/lavalink-api-client-1.0.1.tgz",
|
||||
"integrity": "sha512-ur4rrOf68mEKQQ6SwDdzG/8W+ew6zpguLPxny14DjEGxDz/mXvDtILovXpFRR5S4d8Ko9xZygIJ9YqEQfgKC/w==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.0"
|
||||
},
|
||||
@ -2501,6 +2479,7 @@
|
||||
"resolved": "https://registry.npmjs.org/lavalink-protocol/-/lavalink-protocol-1.0.2.tgz",
|
||||
"integrity": "sha512-OLd4ZDrYeT35UxJY1K/Pu6PjqPnHN0X5HutcQ7E/UNz+3YBvieaki9z0gk08gPwsxkBhYjRKDNIVNTAT0sH0fA==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@effect/data": "0.17.6",
|
||||
"@effect/schema": "^0.49.4",
|
||||
@ -2515,6 +2494,7 @@
|
||||
"resolved": "https://registry.npmjs.org/lavalink-ws-client/-/lavalink-ws-client-1.0.1.tgz",
|
||||
"integrity": "sha512-jXntoMJe/lk4vuO3RVfSVQPNx28CwammqP4I3+pi5uIF/WHBAJxzwyIzDCmUPIIXcuEveUH53bs2aE8uCq9Sig==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.0",
|
||||
"typed-emitter": "^2.1.0",
|
||||
@ -2528,6 +2508,20 @@
|
||||
"lavalink-protocol": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lavalink-client": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/lavalink-client/-/lavalink-client-2.4.1.tgz",
|
||||
"integrity": "sha512-wrRkbzILdjRzadAbdGM9O3bgLEabAebGci2YOUCcQoCumEjAMPz+rj7Xepa+y0oydnodyYZvBrB9ZeSdy7rzuw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.7.0",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lavalink-protocol": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lavalink-protocol/-/lavalink-protocol-1.0.1.tgz",
|
||||
@ -3597,6 +3591,7 @@
|
||||
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
@ -4150,9 +4145,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/twemoji-parser": {
|
||||
@ -4204,6 +4199,7 @@
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
|
||||
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"optionalDependencies": {
|
||||
"rxjs": "*"
|
||||
}
|
||||
@ -4356,9 +4352,10 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TinashaBot",
|
||||
"version": "5.6.2",
|
||||
"version": "5.7.0",
|
||||
"description": "multipurpose discord bot built using discord-js",
|
||||
"main": "bot.js",
|
||||
"author": "Amane",
|
||||
@ -24,8 +24,6 @@
|
||||
"dependencies": {
|
||||
"@google/generative-ai": "^0.14.0",
|
||||
"@lavaclient/plugin-queue": "^0.0.1",
|
||||
"@lavaclient/queue": "^2.1.1",
|
||||
"@lavaclient/spotify": "^3.1.0",
|
||||
"@lavaclient/types": "^2.1.1",
|
||||
"@vitalets/google-translate-api": "^9.2.0",
|
||||
"common-tags": "^1.8.2",
|
||||
@ -41,7 +39,7 @@
|
||||
"express-session": "^1.18.0",
|
||||
"fixedsize-map": "^1.0.1",
|
||||
"iso-639-1": "^3.1.0",
|
||||
"lavaclient": "^5.0.0-rc.3",
|
||||
"lavalink-client": "^2.4.0",
|
||||
"module-alias": "^2.2.3",
|
||||
"moment": "^2.30.1",
|
||||
"mongoose": "^8.1.1",
|
||||
|
51
src/commands/music/autoplay.js
Normal file
51
src/commands/music/autoplay.js
Normal file
@ -0,0 +1,51 @@
|
||||
const { musicValidations } = require("@helpers/BotUtils");
|
||||
const { autoplayFunction } = require("@handlers/player");
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
*/
|
||||
module.exports = {
|
||||
name: "autoplay",
|
||||
description: "Toggle autoplay feature for music player",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["ap"],
|
||||
usage: "",
|
||||
},
|
||||
slashCommand: {
|
||||
enabled: true,
|
||||
options: [],
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const response = await toggleAutoplay(message);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const response = await toggleAutoplay(interaction);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
|
||||
async function toggleAutoplay({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No song is currently playing";
|
||||
}
|
||||
|
||||
const autoplayState = player.get("autoplay");
|
||||
|
||||
if (autoplayState) {
|
||||
player.set("autoplay", false);
|
||||
return "Autoplay deactivated";
|
||||
}
|
||||
|
||||
player.set("autoplay", true);
|
||||
autoplayFunction(client, player.queue.current, player);
|
||||
|
||||
return "Autoplay activated!";
|
||||
}
|
@ -1,23 +1,18 @@
|
||||
const { musicValidations } = require("@helpers/BotUtils");
|
||||
const { ApplicationCommandOptionType } = require("discord.js");
|
||||
|
||||
const levels = {
|
||||
none: 0.0,
|
||||
low: 0.1,
|
||||
medium: 0.15,
|
||||
high: 0.25,
|
||||
};
|
||||
const { EQList } = require("lavalink-client");
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
*/
|
||||
module.exports = {
|
||||
name: "bassboost",
|
||||
description: "set bassboost level",
|
||||
description: "Set bassboost level",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["bb"],
|
||||
minArgsCount: 1,
|
||||
usage: "<none|low|medium|high>",
|
||||
},
|
||||
@ -30,48 +25,64 @@ module.exports = {
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
choices: [
|
||||
{
|
||||
name: "none",
|
||||
value: "none",
|
||||
},
|
||||
{
|
||||
name: "low",
|
||||
value: "low",
|
||||
},
|
||||
{
|
||||
name: "medium",
|
||||
value: "medium",
|
||||
},
|
||||
{
|
||||
name: "high",
|
||||
value: "high",
|
||||
},
|
||||
{ name: "High", value: "high" },
|
||||
{ name: "Medium", value: "medium" },
|
||||
{ name: "Low", value: "low" },
|
||||
{ name: "Off", value: "off" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
let level = "none";
|
||||
if (args.length && args[0].toLowerCase() in levels) level = args[0].toLowerCase();
|
||||
const response = setBassBoost(message, level);
|
||||
let level = "off";
|
||||
if (args.length) {
|
||||
const input = args[0].toLowerCase();
|
||||
if (["high", "medium", "low", "off"].includes(input)) {
|
||||
level = input;
|
||||
}
|
||||
}
|
||||
const response = await setBassBoost(message, level);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
let level = interaction.options.getString("level");
|
||||
const response = setBassBoost(interaction, level);
|
||||
const response = await setBassBoost(interaction, level);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
* @param {number} level
|
||||
* @param {string} level
|
||||
*/
|
||||
function setBassBoost({ client, guildId }, level) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
const bands = new Array(3).fill(null).map((_, i) => ({ band: i, gain: levels[level] }));
|
||||
player.setFilters(...bands);
|
||||
async function setBassBoost({ client, guildId }, level) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No song is currently playing";
|
||||
}
|
||||
|
||||
// Clear any existing EQ
|
||||
await player.filterManager.clearEQ();
|
||||
|
||||
switch (level) {
|
||||
case "high":
|
||||
await player.filterManager.setEQ(EQList.BassboostHigh);
|
||||
break;
|
||||
case "medium":
|
||||
await player.filterManager.setEQ(EQList.BassboostMedium);
|
||||
break;
|
||||
case "low":
|
||||
await player.filterManager.setEQ(EQList.BassboostLow);
|
||||
break;
|
||||
case "off":
|
||||
await player.filterManager.clearEQ();
|
||||
break;
|
||||
default:
|
||||
return "Invalid bassboost level";
|
||||
}
|
||||
|
||||
return `> Set the bassboost level to \`${level}\``;
|
||||
}
|
||||
|
41
src/commands/music/leave.js
Normal file
41
src/commands/music/leave.js
Normal file
@ -0,0 +1,41 @@
|
||||
const { musicValidations } = require("@helpers/BotUtils");
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
*/
|
||||
module.exports = {
|
||||
name: "leave",
|
||||
description: "Disconnects the bot from the voice channel",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["dc"],
|
||||
minArgsCount: 0,
|
||||
usage: "",
|
||||
},
|
||||
slashCommand: {
|
||||
enabled: true,
|
||||
options: [],
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const response = await leave(message);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const response = await leave(interaction);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
async function leave({ client, guildId, member }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
player.destroy();
|
||||
return "👋 Disconnected from the voice channel";
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
const { musicValidations } = require("@helpers/BotUtils");
|
||||
const { LoopType } = require("@lavaclient/plugin-queue");
|
||||
const { ApplicationCommandOptionType } = require("discord.js");
|
||||
|
||||
/**
|
||||
@ -12,8 +11,9 @@ module.exports = {
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["lp"],
|
||||
minArgsCount: 1,
|
||||
usage: "<queue|track>",
|
||||
usage: "<queue|track|off>",
|
||||
},
|
||||
slashCommand: {
|
||||
enabled: true,
|
||||
@ -21,17 +21,12 @@ module.exports = {
|
||||
{
|
||||
name: "type",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
description: "The entity you want to loop",
|
||||
description: "Select loop type",
|
||||
required: false,
|
||||
choices: [
|
||||
{
|
||||
name: "queue",
|
||||
value: "queue",
|
||||
},
|
||||
{
|
||||
name: "track",
|
||||
value: "track",
|
||||
},
|
||||
{ name: "Track", value: "track" },
|
||||
{ name: "Queue", value: "queue" },
|
||||
{ name: "Off", value: "off" },
|
||||
],
|
||||
},
|
||||
],
|
||||
@ -39,34 +34,47 @@ module.exports = {
|
||||
|
||||
async messageRun(message, args) {
|
||||
const input = args[0].toLowerCase();
|
||||
const type = input === "queue" ? "queue" : "track";
|
||||
const response = toggleLoop(message, type);
|
||||
const type = input === "queue" ? "queue" : input === "track" ? "track" : "off";
|
||||
const response = await toggleLoop(message, type);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const type = interaction.options.getString("type") || "track";
|
||||
const response = toggleLoop(interaction, type);
|
||||
const response = await toggleLoop(interaction, type);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
* @param {"queue"|"track"} type
|
||||
* @param {"queue"|"track"|"off"} type
|
||||
*/
|
||||
function toggleLoop({ client, guildId }, type) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
async function toggleLoop({ client, guildId }, type) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
// track
|
||||
if (type === "track") {
|
||||
player.queue.setLoop(LoopType.Song);
|
||||
return "Loop mode is set to `track`";
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No song is currently playing";
|
||||
}
|
||||
|
||||
// queue
|
||||
else if (type === "queue") {
|
||||
player.queue.setLoop(LoopType.Queue);
|
||||
return "Loop mode is set to `queue`";
|
||||
switch (type) {
|
||||
case "track":
|
||||
player.setRepeatMode("track");
|
||||
return "Loop mode is set to `track`";
|
||||
|
||||
case "queue":
|
||||
if (player.queue.tracks.length > 1) {
|
||||
player.setRepeatMode("queue");
|
||||
return "Loop mode is set to `queue`";
|
||||
} else {
|
||||
return "🚫 Queue is too short to be looped";
|
||||
}
|
||||
|
||||
case "off":
|
||||
player.setRepeatMode("off");
|
||||
return "Loop mode is disabled";
|
||||
|
||||
default:
|
||||
return "Invalid loop type";
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ async function getLyric({ client, guild, member }, query) {
|
||||
|
||||
try {
|
||||
if (!query) {
|
||||
/** @type { import('lavaclient').Player } */
|
||||
/** @type { import('lavalink-client').Player } */
|
||||
const player = client.musicManager.players.resolve(guild.id);
|
||||
|
||||
if (!player?.track) return "🚫 There's no active music player in this server.";
|
||||
|
@ -1,13 +1,13 @@
|
||||
const { EMBED_COLORS } = require("@root/config");
|
||||
const { EmbedBuilder } = require("discord.js");
|
||||
const { formatTime } = require("@helpers/Utils");
|
||||
const { splitBar } = require("string-progressbar");
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
*/
|
||||
module.exports = {
|
||||
name: "np",
|
||||
description: "show's what track is currently being played",
|
||||
description: "Shows what track is currently being played",
|
||||
category: "MUSIC",
|
||||
botPermissions: ["EmbedLinks"],
|
||||
command: {
|
||||
@ -18,7 +18,7 @@ module.exports = {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
async messageRun(message) {
|
||||
async messageRun(message, args) {
|
||||
const response = nowPlaying(message);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
@ -32,35 +32,38 @@ module.exports = {
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function nowPlaying({ client, guildId, member }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
if (!player || !player.queue.current) return "🚫 No music is being played!";
|
||||
function nowPlaying({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No music is being played!";
|
||||
}
|
||||
|
||||
const track = player.queue.current;
|
||||
const totalLength = track.info.length;
|
||||
const position = player.position;
|
||||
const progress = Math.round((position / totalLength) * 15);
|
||||
const progressBar = `${formatTime(position)} [${"▬".repeat(
|
||||
progress)}🔘${"▬".repeat(15 - progress)}] ${formatTime(totalLength)}`;
|
||||
const end = track.info.isStream ? "Live" : client.utils.formatTime(track.info.duration);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setAuthor({ name: "Now playing" })
|
||||
.setAuthor({ name: "Now Playing" })
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.addFields(
|
||||
{
|
||||
name: "Song Duration",
|
||||
value: `\`${formatTime(track.info.length)}\``,
|
||||
value: client.utils.formatTime(track.info.duration),
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Requested By",
|
||||
value: track.requesterId ? track.requesterId : member.user.displayName,
|
||||
value: track.requester.displayName || "Unknown",
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "\u200b",
|
||||
value: progressBar,
|
||||
value:
|
||||
client.utils.formatTime(player.position) +
|
||||
" [" +
|
||||
splitBar(track.info.isStream ? player.position : track.info.duration, player.position, 15)[0] +
|
||||
"] " +
|
||||
end,
|
||||
inline: false,
|
||||
}
|
||||
);
|
||||
|
@ -5,7 +5,7 @@ const { musicValidations } = require("@helpers/BotUtils");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "pause",
|
||||
description: "pause the music player",
|
||||
description: "Pause the music player",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
@ -16,12 +16,12 @@ module.exports = {
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const response = pause(message);
|
||||
const response = await pause(message);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const response = pause(interaction);
|
||||
const response = await pause(interaction);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -29,10 +29,17 @@ module.exports = {
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function pause({ client, guildId }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
if (player.paused) return "The player is already paused.";
|
||||
async function pause({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
player.pause(true);
|
||||
return "⏸️ Paused the music player.";
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No song is currently playing";
|
||||
}
|
||||
|
||||
if (player.paused) {
|
||||
return "The player is already paused";
|
||||
}
|
||||
|
||||
player.pause();
|
||||
return "⏸️ Paused the music player";
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js");
|
||||
const { formatTime } = require("@helpers/Utils");
|
||||
require("@lavaclient/plugin-queue")
|
||||
const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
|
||||
/**
|
||||
@ -8,11 +6,12 @@ const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "play",
|
||||
description: "play a song",
|
||||
description: "Play or queue your favorite song!",
|
||||
category: "MUSIC",
|
||||
botPermissions: ["EmbedLinks"],
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["p"],
|
||||
usage: "<song-name>",
|
||||
minArgsCount: 1,
|
||||
},
|
||||
@ -29,14 +28,14 @@ module.exports = {
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const query = args.join(" ");
|
||||
const response = await play(message, query);
|
||||
const searchQuery = args.join(" ");
|
||||
const response = await play(message, searchQuery);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const query = interaction.options.getString("query");
|
||||
const response = await play(interaction, query);
|
||||
const searchQuery = interaction.options.getString("query");
|
||||
const response = await play(interaction, searchQuery);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -45,134 +44,106 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
* @param {string} query
|
||||
*/
|
||||
async function play({ member, guild, channel }, query) {
|
||||
async function play({ member, guild, channel }, searchQuery) {
|
||||
if (!member.voice.channel) return "🚫 You need to join a voice channel first";
|
||||
|
||||
let player = guild.client.musicManager.players.resolve(guild.id);
|
||||
if (player && !guild.members.me.voice.channel) {
|
||||
player.voice.disconnect();
|
||||
await guild.client.musicManager.players.destroy(guild.id);
|
||||
}
|
||||
let player = guild.client.musicManager.getPlayer(guild.id);
|
||||
|
||||
if (player && member.voice.channel !== guild.members.me.voice.channel) {
|
||||
return "🚫 You must be in the same voice channel as mine";
|
||||
}
|
||||
|
||||
let embed = new EmbedBuilder().setColor(EMBED_COLORS.BOT_EMBED);
|
||||
let tracks;
|
||||
let description = "";
|
||||
let thumbnail;
|
||||
if (!player) {
|
||||
player = await guild.client.musicManager.createPlayer({
|
||||
guildId: guild.id,
|
||||
voiceChannelId: member.voice.channel.id,
|
||||
textChannelId: channel.id,
|
||||
selfMute: false,
|
||||
selfDeaf: true,
|
||||
volume: MUSIC.DEFAULT_VOLUME,
|
||||
});
|
||||
}
|
||||
|
||||
if (!player.connected) await player.connect();
|
||||
|
||||
try {
|
||||
const res = await guild.client.musicManager.api.loadTracks(
|
||||
/^https?:\/\//.test(query) ? query : `${MUSIC.DEFAULT_SOURCE}:${query}`
|
||||
);
|
||||
const res = await player.search({ query: searchQuery }, member.user);
|
||||
|
||||
let track;
|
||||
if (!res || res.loadType === "empty") {
|
||||
return `🚫 No results found for "${searchQuery}"`;
|
||||
}
|
||||
|
||||
switch (res.loadType) {
|
||||
switch (res?.loadType) {
|
||||
case "error":
|
||||
guild.client.logger.error("Search Exception", res.data);
|
||||
guild.client.logger.error("Search Exception", res.exception);
|
||||
return "🚫 There was an error while searching";
|
||||
|
||||
case "empty":
|
||||
return `No results found matching ${query}`;
|
||||
case "playlist": {
|
||||
player.queue.add(res.tracks);
|
||||
|
||||
case "playlist":
|
||||
tracks = res.data.tracks;
|
||||
description = res.data.info.name;
|
||||
thumbnail = res.data.pluginInfo.artworkUrl;
|
||||
break;
|
||||
const playlistEmbed = new EmbedBuilder()
|
||||
.setAuthor({ name: "Added Playlist to queue" })
|
||||
.setThumbnail(res.playlist.thumbnail)
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setDescription(`[${res.playlist.name}](${res.playlist.uri})`)
|
||||
.addFields(
|
||||
{ name: "Enqueued", value: `${res.tracks.length} songs`, inline: true },
|
||||
{
|
||||
name: "Playlist duration",
|
||||
value:
|
||||
"`" +
|
||||
guild.client.utils.formatTime(res.tracks.map((t) => t.info.duration).reduce((a, b) => a + b, 0)) +
|
||||
"`",
|
||||
inline: true,
|
||||
}
|
||||
)
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
|
||||
if (!player.playing && player.queue.tracks.length > 0) {
|
||||
await player.play({ paused: false });
|
||||
}
|
||||
|
||||
return { embeds: [playlistEmbed] };
|
||||
}
|
||||
|
||||
case "track":
|
||||
track = res.data;
|
||||
tracks = [track];
|
||||
break;
|
||||
case "search": {
|
||||
const track = res.tracks[0];
|
||||
player.queue.add(track);
|
||||
|
||||
case "search":
|
||||
track = res.data[0];
|
||||
tracks = [track];
|
||||
break;
|
||||
const trackEmbed = new EmbedBuilder()
|
||||
.setAuthor({ name: "Added Track to queue" })
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.setThumbnail(track.info.artworkUrl)
|
||||
.addFields({
|
||||
name: "Song Duration",
|
||||
value: "`" + guild.client.utils.formatTime(track.info.duration) + "`",
|
||||
inline: true,
|
||||
})
|
||||
.setFooter({ text: `Requested By: ${track.requester.displayName}` });
|
||||
|
||||
if (player.queue?.tracks?.length > 1) {
|
||||
trackEmbed.addFields({
|
||||
name: "Position in Queue",
|
||||
value: player.queue.tracks.length.toString(),
|
||||
inline: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (!player.playing && player.queue.tracks.length > 0) {
|
||||
await player.play({ paused: false });
|
||||
}
|
||||
|
||||
return { embeds: [trackEmbed] };
|
||||
}
|
||||
|
||||
default:
|
||||
guild.client.logger.debug("Unknown loadType", res);
|
||||
return "🚫 An error occurred while searching for the song";
|
||||
}
|
||||
|
||||
if (!tracks) guild.client.logger.debug({ query, res });
|
||||
} catch (error) {
|
||||
guild.client.logger.error("Search Exception", typeof error === "object" ? JSON.stringify(error) : error);
|
||||
guild.client.logger.error("Search Exception", JSON.stringify(error));
|
||||
return "🚫 An error occurred while searching for the song";
|
||||
}
|
||||
|
||||
if (!tracks) return "🚫 An error occurred while searching for the song";
|
||||
|
||||
if (tracks.length === 1) {
|
||||
const track = tracks[0];
|
||||
if (!player?.playing && !player?.paused && !player?.queue.tracks.length) {
|
||||
embed.setAuthor({ name: "Added Track to queue" });
|
||||
} else {
|
||||
const fields = [];
|
||||
embed
|
||||
.setAuthor({ name: "Added Track to queue" })
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.setThumbnail(track.info.artworkUrl)
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
|
||||
fields.push({
|
||||
name: "Song Duration",
|
||||
value: "`" + formatTime(track.info.length) + "`",
|
||||
inline: true,
|
||||
});
|
||||
|
||||
if (player?.queue?.tracks?.length > 0) {
|
||||
fields.push({
|
||||
name: "Position in Queue",
|
||||
value: (player.queue.tracks.length + 1).toString(),
|
||||
inline: true,
|
||||
});
|
||||
}
|
||||
embed.addFields(fields);
|
||||
}
|
||||
} else {
|
||||
embed
|
||||
.setAuthor({ name: "Added Playlist to queue" })
|
||||
.setThumbnail(thumbnail)
|
||||
.setDescription(description)
|
||||
.addFields(
|
||||
{
|
||||
name: "Enqueued",
|
||||
value: `${tracks.length} songs`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Playlist duration",
|
||||
value:
|
||||
"`" +
|
||||
formatTime(
|
||||
tracks.map((t) => t.info.length).reduce((a, b) => a + b, 0),
|
||||
) +
|
||||
"`",
|
||||
inline: true,
|
||||
}
|
||||
)
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
}
|
||||
|
||||
// create a player and/or join the member's vc
|
||||
if (!player?.connected) {
|
||||
player = guild.client.musicManager.players.create(guild.id);
|
||||
player.queue.data.channel = channel;
|
||||
player.voice.connect(member.voice.channel.id, { deafened: true });
|
||||
player.setVolume(MUSIC.DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
// do queue things
|
||||
const started = player.playing || player.paused;
|
||||
player.queue.add(tracks, { requester: member.user.displayName, next: false });
|
||||
if (!started) {
|
||||
await player.queue.start();
|
||||
}
|
||||
|
||||
return { embeds: [embed] };
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
const { EMBED_COLORS } = require("@root/config");
|
||||
const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js");
|
||||
const { formatTime } = require("@helpers/Utils");
|
||||
|
||||
/**
|
||||
* @type {import("@structures/Command")}
|
||||
@ -12,6 +11,7 @@ module.exports = {
|
||||
botPermissions: ["EmbedLinks"],
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["q"],
|
||||
usage: "[page]",
|
||||
},
|
||||
slashCommand: {
|
||||
@ -44,46 +44,39 @@ module.exports = {
|
||||
* @param {number} pgNo
|
||||
*/
|
||||
async function getQueue({ client, guild }, pgNo) {
|
||||
const player = client.musicManager.players.resolve(guild.id);
|
||||
if (!player) return "🚫 There is no music playing in this guild.";
|
||||
|
||||
const queue = player.queue;
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setAuthor({ name: `Queue for ${guild.name}` });
|
||||
|
||||
// change for the amount of tracks per page
|
||||
const multiple = 10;
|
||||
const page = pgNo || 1;
|
||||
|
||||
const end = page * multiple;
|
||||
const start = end - multiple;
|
||||
|
||||
const tracks = queue.tracks.slice(start, end);
|
||||
|
||||
if (queue.current) {
|
||||
const currentTrack = queue.current;
|
||||
embed.addFields({
|
||||
name: "Current",
|
||||
value: `[${currentTrack.info.title}](${currentTrack.info.uri}) \`[${formatTime(currentTrack.info.length)}]\``
|
||||
});
|
||||
const player = client.musicManager.getPlayer(guild.id);
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No song is currently playing";
|
||||
}
|
||||
|
||||
const queueList = tracks.map((track, index) => {
|
||||
const title = track.info.title;
|
||||
const uri = track.info.uri;
|
||||
const duration = formatTime(track.info.length);
|
||||
return `${start + index + 1}. [${title}](${uri}) \`[${duration}]\``;
|
||||
});
|
||||
const embed = new EmbedBuilder().setColor(EMBED_COLORS.BOT_EMBED).setAuthor({ name: `Queue for ${guild.name}` });
|
||||
|
||||
if (!queueList.length) {
|
||||
embed.setDescription(`No tracks in ${page > 1 ? `page ${page}` : "the queue"}.`);
|
||||
} else {
|
||||
embed.setDescription(queueList.join("\n"));
|
||||
const end = (pgNo || 1) * 10;
|
||||
const start = end - 10;
|
||||
|
||||
const tracks = player.queue.tracks.slice(start, end);
|
||||
|
||||
if (player.queue.current) {
|
||||
const current = player.queue.current;
|
||||
embed
|
||||
.addFields({
|
||||
name: "Current",
|
||||
value: `[${current.info.title}](${current.info.uri}) \`[${client.utils.formatTime(current.info.duration)}]\``,
|
||||
})
|
||||
.setThumbnail(current.info.artworkUrl);
|
||||
}
|
||||
|
||||
const maxPages = Math.ceil(queue.tracks.length / multiple);
|
||||
embed.setFooter({ text: `Page ${page > maxPages ? maxPages : page} of ${maxPages}` });
|
||||
const queueList = tracks.map(
|
||||
(track, index) =>
|
||||
`${start + index + 1}. [${track.info.title}](${track.info.uri}) \`[${client.utils.formatTime(track.info.duration)}]\``
|
||||
);
|
||||
|
||||
embed.setDescription(
|
||||
queueList.length ? queueList.join("\n") : `No tracks in ${pgNo > 1 ? `page ${pgNo}` : "the queue"}.`
|
||||
);
|
||||
|
||||
const maxPages = Math.ceil(player.queue.tracks.length / 10);
|
||||
embed.setFooter({ text: `Page ${pgNo > maxPages ? maxPages : pgNo} of ${maxPages}` });
|
||||
|
||||
return { embeds: [embed] };
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ const { musicValidations } = require("@helpers/BotUtils");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "resume",
|
||||
description: "resumes the music player",
|
||||
description: "Resumes the music player",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
@ -16,12 +16,12 @@ module.exports = {
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const response = resumePlayer(message);
|
||||
const response = await resumePlayer(message);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const response = resumePlayer(interaction);
|
||||
const response = await resumePlayer(interaction);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -29,9 +29,15 @@ module.exports = {
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function resumePlayer({ client, guildId }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
async function resumePlayer({ client, guildId }) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 No song is currently playing";
|
||||
}
|
||||
|
||||
if (!player.paused) return "The player is already resumed";
|
||||
|
||||
player.resume();
|
||||
return "▶️ Resumed the music player";
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ const {
|
||||
ApplicationCommandOptionType,
|
||||
ComponentType,
|
||||
} = require("discord.js");
|
||||
const { formatTime } = require("@helpers/Utils");
|
||||
const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
|
||||
/**
|
||||
@ -13,11 +12,12 @@ const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "search",
|
||||
description: "search for matching songs",
|
||||
description: "search for matching songs on YouTube",
|
||||
category: "MUSIC",
|
||||
botPermissions: ["EmbedLinks"],
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["sc"],
|
||||
usage: "<song-name>",
|
||||
minArgsCount: 1,
|
||||
},
|
||||
@ -48,171 +48,100 @@ module.exports = {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} interaction
|
||||
* @param {string} query
|
||||
*/
|
||||
async function search({ member, guild, channel }, query) {
|
||||
if (!member.voice.channel) return "🚫 You need to join a voice channel first";
|
||||
if (!member.voice.channel) return "🚫 You need to join a voice channel first";
|
||||
|
||||
let player = guild.client.musicManager.getPlayer(guild.id);
|
||||
|
||||
let player = guild.client.musicManager.players.resolve(guild.id);
|
||||
if (player && !guild.members.me.voice.channel) {
|
||||
player.voice.disconnect();
|
||||
await guild.client.musicManager.players.destroy(guild.id);
|
||||
}
|
||||
if (player && member.voice.channel !== guild.members.me.voice.channel) {
|
||||
return "🚫 You must be in the same voice channel as mine";
|
||||
return "🚫 You must be in the same voice channel as me.";
|
||||
}
|
||||
|
||||
let res;
|
||||
if (!player) {
|
||||
player = await guild.client.musicManager.createPlayer({
|
||||
guildId: guild.id,
|
||||
voiceChannelId: member.voice.channel.id,
|
||||
textChannelId: channel.id,
|
||||
selfMute: false,
|
||||
selfDeaf: true,
|
||||
volume: MUSIC.DEFAULT_VOLUME,
|
||||
});
|
||||
}
|
||||
|
||||
if (!player.connected) await player.connect();
|
||||
|
||||
const res = await player.search({ query }, member.user);
|
||||
|
||||
if (!res || !res.tracks?.length) {
|
||||
return {
|
||||
embeds: [new EmbedBuilder().setColor(EMBED_COLORS.ERROR).setDescription(`No results found for \`${query}\``)],
|
||||
};
|
||||
}
|
||||
|
||||
let maxResults = MUSIC.MAX_SEARCH_RESULTS;
|
||||
if (res.tracks.length < maxResults) maxResults = res.tracks.length;
|
||||
|
||||
const results = res.tracks.slice(0, maxResults);
|
||||
const options = results.map((track, index) => ({
|
||||
label: track.info.title,
|
||||
value: index.toString(),
|
||||
}));
|
||||
|
||||
const menuRow = new ActionRowBuilder().addComponents(
|
||||
new StringSelectMenuBuilder()
|
||||
.setCustomId("search-results")
|
||||
.setPlaceholder("Choose Search Results")
|
||||
.setMaxValues(1)
|
||||
.addOptions(options)
|
||||
);
|
||||
|
||||
const searchEmbed = new EmbedBuilder()
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setAuthor({ name: "Search Results" })
|
||||
.setDescription(`Select the song you wish to add to the queue`);
|
||||
|
||||
const searchMessage = await channel.send({
|
||||
embeds: [searchEmbed],
|
||||
components: [menuRow],
|
||||
});
|
||||
|
||||
try {
|
||||
res = await guild.client.musicManager.api.loadTracks(
|
||||
/^https?:\/\//.test(query) ? query : `${MUSIC.DEFAULT_SOURCE}:${query}`
|
||||
);
|
||||
} catch (err) {
|
||||
return "🚫 There was an error while searching";
|
||||
}
|
||||
const response = await channel.awaitMessageComponent({
|
||||
filter: (i) => i.user.id === member.id && i.message.id === searchMessage.id,
|
||||
componentType: ComponentType.StringSelect,
|
||||
idle: 30 * 1000,
|
||||
});
|
||||
|
||||
let embed = new EmbedBuilder().setColor(EMBED_COLORS.BOT_EMBED);
|
||||
let tracks;
|
||||
if (response.customId !== "search-results") return;
|
||||
|
||||
switch (res.loadType) {
|
||||
case "error":
|
||||
guild.client.logger.error("Search Exception", res.data);
|
||||
return "🚫 There was an error while searching";
|
||||
await searchMessage.delete();
|
||||
if (!response) return "🚫 You took too long to select the songs";
|
||||
|
||||
case "empty":
|
||||
return `No results found matching ${query}`;
|
||||
const selectedTrack = results[response.values[0]];
|
||||
player.queue.add(selectedTrack);
|
||||
|
||||
case "track": {
|
||||
const [track] = res.data[0];
|
||||
tracks = [track];
|
||||
if (!player?.playing && !player?.paused && !player?.queue.tracks.length) {
|
||||
embed.setAuthor({ name: "Added Song to queue" });
|
||||
break;
|
||||
}
|
||||
|
||||
const fields = [];
|
||||
embed
|
||||
.setAuthor({ name: "Added Song to queue" })
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
|
||||
fields.push({
|
||||
const trackEmbed = new EmbedBuilder()
|
||||
.setAuthor({ name: "Added Track to queue" })
|
||||
.setDescription(`[${selectedTrack.info.title}](${selectedTrack.info.uri})`)
|
||||
.setThumbnail(selectedTrack.info.artworkUrl)
|
||||
.addFields({
|
||||
name: "Song Duration",
|
||||
value: "`" + formatTime(track.info.length) + "`",
|
||||
value: "`" + guild.client.utils.formatTime(selectedTrack.info.duration) + "`",
|
||||
inline: true,
|
||||
});
|
||||
})
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
|
||||
if (player?.queue?.tracks?.length > 0) {
|
||||
fields.push({
|
||||
name: "Position in Queue",
|
||||
value: (player.queue.tracks.length + 1).toString(),
|
||||
inline: true,
|
||||
});
|
||||
}
|
||||
embed.addFields(fields);
|
||||
break;
|
||||
if (!player.playing && player.queue.tracks.length > 0) {
|
||||
await player.play({ paused: false });
|
||||
}
|
||||
|
||||
case "playlist":
|
||||
tracks = res.data.tracks;
|
||||
embed
|
||||
.setAuthor({ name: "Added Playlist to queue" })
|
||||
.setDescription(res.data.info.name)
|
||||
.addFields(
|
||||
{
|
||||
name: "Enqueued",
|
||||
value: `${res.data.tracks.length} songs`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Playlist duration",
|
||||
value:
|
||||
"`" +
|
||||
formatTime(
|
||||
res.data.tracks.map((t) => t.info.length).reduce((a, b) => a + b, 0),
|
||||
) +
|
||||
"`",
|
||||
inline: true,
|
||||
}
|
||||
)
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
break;
|
||||
|
||||
case "search": {
|
||||
let max = guild.client.config.MUSIC.MAX_SEARCH_RESULTS;
|
||||
if (res.data.length < max) max = res.data.length;
|
||||
|
||||
const results = res.data.slice(0, max);
|
||||
const options = results.map((result, index) => ({
|
||||
label: result.info.title,
|
||||
value: index.toString(),
|
||||
}));
|
||||
|
||||
const menuRow = new ActionRowBuilder().addComponents(
|
||||
new StringSelectMenuBuilder()
|
||||
.setCustomId("search-results")
|
||||
.setPlaceholder("Choose Search Results")
|
||||
.setMaxValues(max)
|
||||
.addOptions(options)
|
||||
);
|
||||
|
||||
const tempEmbed = new EmbedBuilder()
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setAuthor({ name: "Search Results" })
|
||||
.setDescription(`Please select the songs you wish to add to queue`);
|
||||
|
||||
const sentMsg = await channel.send({
|
||||
embeds: [tempEmbed],
|
||||
components: [menuRow],
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await channel.awaitMessageComponent({
|
||||
filter: (reactor) => reactor.message.id === sentMsg.id && reactor.user.id === member.id,
|
||||
idle: 30 * 1000,
|
||||
componentType: ComponentType.StringSelect,
|
||||
});
|
||||
|
||||
await sentMsg.delete();
|
||||
if (!response) return "🚫 You took too long to select the songs";
|
||||
|
||||
if (response.customId !== "search-results") return;
|
||||
const toAdd = [];
|
||||
response.values.forEach((v) => toAdd.push(results[v]));
|
||||
|
||||
// Only 1 song is selected
|
||||
if (toAdd.length === 1) {
|
||||
tracks = [toAdd[0]];
|
||||
embed.setAuthor({ name: "Added Song to queue" });
|
||||
} else {
|
||||
tracks = toAdd;
|
||||
embed
|
||||
.setDescription(`🎶 Added ${toAdd.length} songs to queue`)
|
||||
.setFooter({ text: `Requested By: ${member.user.displayName}` });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
await sentMsg.delete();
|
||||
return "🚫 Failed to register your response";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return { embeds: [trackEmbed] };
|
||||
} catch (err) {
|
||||
console.error("Error handling response:", err);
|
||||
await searchMessage.delete();
|
||||
return "🚫 Failed to register your response";
|
||||
}
|
||||
|
||||
// create a player and/or join the member's vc
|
||||
if (!player?.connected) {
|
||||
player = guild.client.musicManager.players.create(guild.id);
|
||||
player.queue.data.channel = channel;
|
||||
player.voice.connect(member.voice.channel.id, { deafened: true });
|
||||
}
|
||||
|
||||
// do queue things
|
||||
const started = player.playing || player.paused;
|
||||
player.queue.add(tracks, { requester: member.user.username, next: false });
|
||||
if (!started) {
|
||||
await player.queue.start();
|
||||
}
|
||||
|
||||
return { embeds: [embed] };
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
const { musicValidations } = require("@helpers/BotUtils");
|
||||
const prettyMs = require("pretty-ms");
|
||||
const { durationToMillis } = require("@helpers/Utils");
|
||||
const { ApplicationCommandOptionType } = require("discord.js");
|
||||
|
||||
/**
|
||||
@ -8,7 +6,7 @@ const { ApplicationCommandOptionType } = require("discord.js");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "seek",
|
||||
description: "sets the playing track's position to the specified position",
|
||||
description: "Sets the position of the current track",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
@ -20,7 +18,7 @@ module.exports = {
|
||||
options: [
|
||||
{
|
||||
name: "time",
|
||||
description: "The time you want to seek to.",
|
||||
description: "The time you want to seek to",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
@ -28,14 +26,20 @@ module.exports = {
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const time = args.join(" ");
|
||||
const response = seekTo(message, time);
|
||||
const time = message.client.utils.parseTime(args.join(" "));
|
||||
if (!time) {
|
||||
return await message.safeReply("Invalid time format. Use 10s, 1m 50s, 1h");
|
||||
}
|
||||
const response = await seekTo(message, time);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const time = interaction.options.getString("time");
|
||||
const response = seekTo(interaction, time);
|
||||
const time = interaction.client.utils.parseTime(interaction.options.getString("time"));
|
||||
if (!time) {
|
||||
return await interaction.followUp("Invalid time format. Use 10s, 1m 50s, 1h");
|
||||
}
|
||||
const response = await seekTo(interaction, time);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -44,14 +48,17 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
* @param {number} time
|
||||
*/
|
||||
function seekTo({ client, guildId }, time) {
|
||||
const player = client.musicManager?.players.resolve(guildId);
|
||||
const seekTo = durationToMillis(time);
|
||||
async function seekTo({ client, guildId }, time) {
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (seekTo > player.queue.current.info.length) {
|
||||
return "The duration you provide exceeds the duration of the current track";
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 There's no music currently playing";
|
||||
}
|
||||
|
||||
player.seek(seekTo);
|
||||
return `Seeked to ${prettyMs(seekTo, { colonNotation: true, secondsDecimalDigits: 0 })}`;
|
||||
if (time > player.queue.current.length) {
|
||||
return "The duration you provided exceeds the duration of the current track";
|
||||
}
|
||||
|
||||
player.seek(time);
|
||||
return `Seeked song duration to **${client.utils.formatTime(time)}**`;
|
||||
}
|
||||
|
@ -30,7 +30,16 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
function shuffle({ client, guildId }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!player || !player.queue.curren) {
|
||||
return "🚫 There's no music currently playing";
|
||||
}
|
||||
|
||||
if (player.queue.tracks.length < 2) {
|
||||
return "🚫 Not enough tracks to shuffle";
|
||||
}
|
||||
|
||||
player.queue.shuffle();
|
||||
return "🎶 Queue has been shuffled";
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ const { musicValidations } = require("@helpers/BotUtils");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "skip",
|
||||
description: "skip the current song",
|
||||
description: "Skip the current song",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["next"],
|
||||
aliases: ["next", "s"],
|
||||
},
|
||||
slashCommand: {
|
||||
enabled: true,
|
||||
@ -31,20 +31,18 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
async function skip({ client, guildId }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!player || !player.queue.current) {
|
||||
return "There is no song currently being played.";
|
||||
return "🚫 There's no music currently playing";
|
||||
}
|
||||
|
||||
|
||||
const title = player.queue.current.info.title;
|
||||
|
||||
// Check if there is a next song in the queue
|
||||
if (player.queue.tracks.length === 0) {
|
||||
return "There is no next song to skip to.";
|
||||
}
|
||||
if (player.queue.tracks.length === 0) {
|
||||
return "There is no next song to skip to";
|
||||
}
|
||||
|
||||
// Skip to the next song
|
||||
player.queue.next();
|
||||
return `⏯️ ${title} was skipped successfully.`;
|
||||
}
|
||||
await player.skip();
|
||||
return `⏯️ ${title} was skipped`;
|
||||
}
|
||||
|
@ -5,24 +5,24 @@ const { musicValidations } = require("@helpers/BotUtils");
|
||||
*/
|
||||
module.exports = {
|
||||
name: "stop",
|
||||
description: "stop the music player",
|
||||
description: "Stop the music player",
|
||||
category: "MUSIC",
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
aliases: ["leave"],
|
||||
aliases: [""],
|
||||
},
|
||||
slashCommand: {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
async messageRun(message, args) {
|
||||
const response = await stop(message);
|
||||
async messageRun(message, args, data) {
|
||||
const response = await stop(message, data.settings);
|
||||
await message.safeReply(response);
|
||||
},
|
||||
|
||||
async interactionRun(interaction) {
|
||||
const response = await stop(interaction);
|
||||
async interactionRun(interaction, data) {
|
||||
const response = await stop(interaction, data.settings);
|
||||
await interaction.followUp(response);
|
||||
},
|
||||
};
|
||||
@ -31,8 +31,17 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
async function stop({ client, guildId }) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
player.voice.disconnect();
|
||||
await client.musicManager.players.destroy(guildId);
|
||||
return "🎶 The music player is stopped and queue has been cleared";
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 There's no music currently playing";
|
||||
}
|
||||
|
||||
if (player.get("autoplay") === true) {
|
||||
player.set("autoplay", false);
|
||||
}
|
||||
|
||||
player.stopPlaying(true, false);
|
||||
|
||||
return "🎶 The music player is stopped, and the queue has been cleared";
|
||||
}
|
||||
|
@ -11,14 +11,15 @@ module.exports = {
|
||||
validations: musicValidations,
|
||||
command: {
|
||||
enabled: true,
|
||||
usage: "<1-100>",
|
||||
aliases: ["vol"],
|
||||
usage: "<0-100>",
|
||||
},
|
||||
slashCommand: {
|
||||
enabled: true,
|
||||
options: [
|
||||
{
|
||||
name: "amount",
|
||||
description: "Enter a value to set [1 to 100]",
|
||||
description: "Enter a value to set [0 to 100]",
|
||||
type: ApplicationCommandOptionType.Integer,
|
||||
required: false,
|
||||
},
|
||||
@ -42,15 +43,19 @@ module.exports = {
|
||||
* @param {import("discord.js").CommandInteraction|import("discord.js").Message} arg0
|
||||
*/
|
||||
async function getVolume({ client, guildId }, amount) {
|
||||
const player = client.musicManager.players.resolve(guildId);
|
||||
const player = client.musicManager.getPlayer(guildId);
|
||||
|
||||
if (!amount) return `> The player volume is \`${player.volume}\`.`;
|
||||
if (!player || !player.queue.current) {
|
||||
return "🚫 There's no music currently playing";
|
||||
}
|
||||
|
||||
if (!amount) return `> The player volume is \`${player.volume}\``;
|
||||
|
||||
if (isNaN(amount) || amount < 0 || amount > 100) {
|
||||
return "You need to give me a volume between 1 and 100.";
|
||||
return "You need to give me a volume between 0 and 100";
|
||||
}
|
||||
|
||||
// Set the player volume
|
||||
await player.setVolume(amount);
|
||||
return `🎶 Music player volume is set to \`${amount}\`.`;
|
||||
return `🎶 Music player volume is set to \`${amount}\``;
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ async function fetchNodesAndTurnItToTable(nodes) {
|
||||
const res = await fetchNodeStat(node).then(HttpUtil.assertStatusOk)
|
||||
stat = await res.json()
|
||||
} catch(e) {
|
||||
error(node.identifier, e)
|
||||
error(node.id, e)
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
const { uptime, memory: { free, reservable }, cpu: { lavalinkLoad }, playingPlayers, players } = stat
|
||||
return {
|
||||
name: `:green_circle: ${node.identifier}`,
|
||||
name: `:green_circle: ${node.id}`,
|
||||
value: [
|
||||
`❯ **Uptime**: ${Utils.formatTime(uptime)}`,
|
||||
`❯ **Memory**: ${byteUnit(free)} (${(free / reservable * 100).toPrecision(3)}%) of ${byteUnit(reservable)}`,
|
||||
@ -57,7 +57,7 @@ async function fetchNodesAndTurnItToTable(nodes) {
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: `:red_circle: ${node.identifier}`,
|
||||
name: `:red_circle: ${node.id}`,
|
||||
value: 'Node is offline'
|
||||
}
|
||||
}
|
||||
@ -71,13 +71,13 @@ async function fetchNodesAndTurnItToTable(nodes) {
|
||||
}
|
||||
|
||||
async function fetchNodeStat(node, connTimeout = 5000) {
|
||||
const baseUrl = (node.info.port !== 80 && node.info.secure)
|
||||
? `https://${node.info.host}:${node.info.port}`
|
||||
: `http://${node.info.host}:${node.info.port}`;
|
||||
const baseUrl = (node.port !== 80 && node.secure)
|
||||
? `https://${node.host}:${node.port}`
|
||||
: `http://${node.host}:${node.port}`;
|
||||
|
||||
return HttpUtil.fetchWithConnTimeout(
|
||||
`${baseUrl}/v4/stats`,
|
||||
{ headers: { Authorization: node.info.auth } },
|
||||
{ headers: { Authorization: node.authorization } },
|
||||
connTimeout
|
||||
);
|
||||
}
|
||||
|
13
src/events/player/playerDestroy.js
Normal file
13
src/events/player/playerDestroy.js
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports = async (client, player) => {
|
||||
const guild = client.guilds.cache.get(player.guildId);
|
||||
if (!guild) return;
|
||||
|
||||
if (player.voiceChannelId) {
|
||||
await client.utils.setVoiceStatus(client, player.voiceChannelId, "");
|
||||
}
|
||||
|
||||
const msg = player.get("message");
|
||||
if (msg && msg.deletable) {
|
||||
await msg.delete().catch(() => {});
|
||||
}
|
||||
};
|
13
src/events/player/playerDisconnect.js
Normal file
13
src/events/player/playerDisconnect.js
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports = async (client, player) => {
|
||||
const guild = client.guilds.cache.get(player.guildId);
|
||||
if (!guild) return;
|
||||
|
||||
if (player.voiceChannelId) {
|
||||
await client.utils.setVoiceStatus(client, player.voiceChannelId, "");
|
||||
}
|
||||
|
||||
const msg = player.get("message");
|
||||
if (msg && msg.deletable) {
|
||||
await msg.delete().catch(() => {});
|
||||
}
|
||||
};
|
30
src/events/player/queueEnd.js
Normal file
30
src/events/player/queueEnd.js
Normal file
@ -0,0 +1,30 @@
|
||||
const { MUSIC, EMBED_COLORS } = require("@root/config");
|
||||
const { EmbedBuilder } = require("discord.js");
|
||||
|
||||
module.exports = async (client, player) => {
|
||||
const guild = client.guilds.cache.get(player.guildId);
|
||||
if (!guild) return;
|
||||
|
||||
if (player.voiceChannelId) {
|
||||
await client.utils.setVoiceStatus(client, player.voiceChannelId, "Silence? Use /play to start the beat!");
|
||||
}
|
||||
|
||||
if (player.volume > 100) {
|
||||
await player.setVolume(MUSIC.DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
const msg = player.get("message");
|
||||
if (msg && msg.deletable) {
|
||||
await msg.delete().catch(() => {});
|
||||
}
|
||||
|
||||
const channel = guild.channels.cache.get(player.textChannelId);
|
||||
if (channel) {
|
||||
await channel.safeSend(
|
||||
{
|
||||
embeds: [new EmbedBuilder().setColor(EMBED_COLORS.BOT_EMBED).setDescription("Queue has ended.")],
|
||||
},
|
||||
10
|
||||
);
|
||||
}
|
||||
};
|
20
src/events/player/trackEnd.js
Normal file
20
src/events/player/trackEnd.js
Normal file
@ -0,0 +1,20 @@
|
||||
const { autoplayFunction } = require("@handlers/player");
|
||||
const { MUSIC } = require("@root/config.js");
|
||||
|
||||
module.exports = async (client, player, track) => {
|
||||
const guild = client.guilds.cache.get(player.guildId);
|
||||
if (!guild) return;
|
||||
|
||||
if (player.volume > 100) {
|
||||
await player.setVolume(MUSIC.DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
const msg = player.get("message");
|
||||
if (msg && msg.deletable) {
|
||||
await msg.delete().catch(() => {});
|
||||
}
|
||||
|
||||
if (player.get("autoplay") === true) {
|
||||
await autoplayFunction(client, track, player);
|
||||
}
|
||||
};
|
112
src/events/player/trackStart.js
Normal file
112
src/events/player/trackStart.js
Normal file
@ -0,0 +1,112 @@
|
||||
const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require("discord.js");
|
||||
const { EMBED_COLORS } = require("@root/config");
|
||||
|
||||
module.exports = async (client, player, track) => {
|
||||
const guild = client.guilds.cache.get(player.guildId);
|
||||
if (!guild) return;
|
||||
|
||||
if (!player.textChannelId || !track) return;
|
||||
|
||||
const channel = guild.channels.cache.get(player.textChannelId);
|
||||
if (!channel) return;
|
||||
|
||||
if (player.get("autoplay") === true) {
|
||||
await player.queue.previous.push(track);
|
||||
}
|
||||
|
||||
if (player.voiceChannelId) {
|
||||
await client.utils.setVoiceStatus(client, player.voiceChannelId, `Paying: **${track.info.title}**`);
|
||||
}
|
||||
|
||||
const previous = await player.queue.shiftPrevious();
|
||||
|
||||
const row = (player) =>
|
||||
new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder().setCustomId("previous").setEmoji("⏪").setStyle(ButtonStyle.Secondary).setDisabled(!previous),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("pause")
|
||||
.setEmoji(player.paused ? "▶️" : "⏸️")
|
||||
.setStyle(player.paused ? ButtonStyle.Success : ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId("stop").setEmoji("⏹️").setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId("skip").setEmoji("⏩").setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder().setCustomId("shuffle").setEmoji("🔀").setStyle(ButtonStyle.Secondary)
|
||||
);
|
||||
|
||||
const msg = await channel.safeSend({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setColor(EMBED_COLORS.BOT_EMBED)
|
||||
.setAuthor({ name: "Track Started" })
|
||||
.setDescription(`🎶 **Now playing [${track.info.title}](${track.info.uri})**`)
|
||||
.setThumbnail(track.info.artworkUrl)
|
||||
.setFooter({
|
||||
text: `Requested by: ${track.requester.displayName}`,
|
||||
})
|
||||
.addFields(
|
||||
{
|
||||
name: "Duration",
|
||||
value: track.info.isStream ? "Live" : client.utils.formatTime(track.info.duration),
|
||||
inline: true,
|
||||
},
|
||||
{ name: "Author", value: track.info.author || "Unknown", inline: true }
|
||||
),
|
||||
],
|
||||
components: [row(player)],
|
||||
});
|
||||
|
||||
if (msg) player.set("message", msg);
|
||||
|
||||
const collector = msg.createMessageComponentCollector({
|
||||
filter: async (int) => {
|
||||
const sameVc = int.guild.members.me.voice.channelId === int.member.voice.channelId;
|
||||
return sameVc;
|
||||
},
|
||||
});
|
||||
|
||||
collector.on("collect", async (int) => {
|
||||
if (!int.isButton()) return;
|
||||
|
||||
await int.deferReply({ ephemeral: true });
|
||||
let description;
|
||||
|
||||
switch (int.customId) {
|
||||
case "previous":
|
||||
description = previous ? "Playing the previous track..." : "No previous track available";
|
||||
if (previous) player.play({ clientTrack: previous });
|
||||
break;
|
||||
|
||||
case "pause":
|
||||
if (player.paused) {
|
||||
player.resume();
|
||||
description = "Track resumed";
|
||||
} else {
|
||||
player.pause();
|
||||
description = "Track paused";
|
||||
}
|
||||
await msg.edit({ components: [row(player)] });
|
||||
break;
|
||||
|
||||
case "stop":
|
||||
player.stopPlaying(true, false);
|
||||
description = "Playback stopped";
|
||||
break;
|
||||
|
||||
case "skip":
|
||||
description = player.queue.tracks.length > 0 ? "Skipped to the next track" : "The queue is empty!";
|
||||
if (player.queue.tracks.length > 0) player.skip();
|
||||
break;
|
||||
|
||||
case "shuffle":
|
||||
if (player.queue.tracks.length < 2) {
|
||||
description = "The queue is too short to shuffle!";
|
||||
} else {
|
||||
player.queue.shuffle();
|
||||
description = "The queue has been shuffled!";
|
||||
}
|
||||
break;
|
||||
}
|
||||
await int.followUp({
|
||||
embeds: [new EmbedBuilder().setDescription(description).setColor(EMBED_COLORS.BOT_EMBED)],
|
||||
});
|
||||
});
|
||||
};
|
3
src/events/raw.js
Normal file
3
src/events/raw.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = async (client, data) => {
|
||||
client.musicManager.sendRawData(data);
|
||||
};
|
@ -10,7 +10,7 @@ module.exports = async (client) => {
|
||||
|
||||
// Initialize Music Manager
|
||||
if (client.config.MUSIC.ENABLED) {
|
||||
client.musicManager.connect({ userId: client.user.id });
|
||||
client.musicManager.init({ ...client.user, shards: "auto" });
|
||||
client.logger.success("Music Manager initialized");
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ module.exports = async (client, oldState, newState) => {
|
||||
// if 1 (you), wait 1 minute
|
||||
if (!oldState.channel.members.size - 1) {
|
||||
const player = client.musicManager.players.resolve(guild.id);
|
||||
if (player) client.musicManager.players.destroy(guild.id).then(player.voice.disconnect()); // destroy the player
|
||||
if (player) client.musicManager.getPlayer(guild.id).destroy(); // destroy the player
|
||||
}
|
||||
}, client.config.MUSIC.IDLE_TIME * 1000);
|
||||
}
|
||||
|
@ -11,4 +11,6 @@ module.exports = {
|
||||
suggestionHandler: require("./suggestion"),
|
||||
ticketHandler: require("./ticket"),
|
||||
translationHandler: require("./translation"),
|
||||
managerHandler: require("./manager"),
|
||||
playerHandler: require("./player"),
|
||||
};
|
||||
|
@ -1,75 +0,0 @@
|
||||
const { EmbedBuilder, GatewayDispatchEvents } = require("discord.js");
|
||||
const { Cluster } = require("lavaclient");
|
||||
const { formatTime } = require("@helpers/Utils");
|
||||
require("@lavaclient/plugin-queue").load();
|
||||
|
||||
/**
|
||||
* @param {import("@structures/BotClient")} client
|
||||
*/
|
||||
module.exports = (client) => {
|
||||
const lavaclient = new Cluster({
|
||||
nodes: client.config.MUSIC.LAVALINK_NODES,
|
||||
ws: client.config.MUSIC.LAVALINK_WS,
|
||||
discord: {
|
||||
sendGatewayCommand: (id, payload) => client.guilds.cache.get(id)?.shard?.send(payload),
|
||||
},
|
||||
});
|
||||
|
||||
client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => lavaclient.players.handleVoiceUpdate(data));
|
||||
client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => lavaclient.players.handleVoiceUpdate(data));
|
||||
|
||||
lavaclient.on("nodeConnected", (node, event) => {
|
||||
client.logger.log(`Node "${node.identifier}" connected`);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeDisconnected", (node, event) => {
|
||||
client.logger.log(`Node "${node.identifier}" disconnected`);
|
||||
const reconnectInterval = 20000; // Time in MS, change as needed.
|
||||
setTimeout(() => {
|
||||
node.connect();
|
||||
}, reconnectInterval);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeError", (node, error) => {
|
||||
client.logger.error(`Node "${node.identifier}" encountered an error: ${error.message}.`, error);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeDebug", (node, event) => {
|
||||
client.logger.debug(`Node "${node.identifier}" debug: ${event.message}`);
|
||||
});
|
||||
|
||||
lavaclient.on("nodeTrackStart", async (_node, queue, track) => {
|
||||
const fields = [];
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({ name: "Now Playing" })
|
||||
.setColor(client.config.EMBED_COLORS.BOT_EMBED)
|
||||
.setDescription(`[${track.info.title}](${track.info.uri})`)
|
||||
.setFooter({ text: `Requested By: ${track.requesterId}` })
|
||||
.setThumbnail(track.info.artworkUrl);
|
||||
|
||||
fields.push({
|
||||
name: "Song Duration",
|
||||
value: "`" + formatTime(track.info.length) + "`",
|
||||
inline: true,
|
||||
});
|
||||
|
||||
if (queue.tracks.length > 0) {
|
||||
fields.push({
|
||||
name: "Position in Queue",
|
||||
value: (queue.tracks.length + 1).toString(),
|
||||
inline: true,
|
||||
});
|
||||
}
|
||||
|
||||
embed.setFields(fields);
|
||||
queue.data.channel.safeSend({ embeds: [embed] });
|
||||
});
|
||||
|
||||
lavaclient.on("nodeQueueFinish", async (_node, queue) => {
|
||||
queue.data.channel.safeSend("Queue has ended.");
|
||||
await client.musicManager.players.destroy(queue.player.guildId).then(() => queue.player.voice.disconnect());
|
||||
});
|
||||
|
||||
return lavaclient;
|
||||
};
|
43
src/handlers/manager.js
Normal file
43
src/handlers/manager.js
Normal file
@ -0,0 +1,43 @@
|
||||
const { LavalinkManager } = require("lavalink-client");
|
||||
const { MUSIC } = require("@root/config.js");
|
||||
|
||||
class Manager extends LavalinkManager {
|
||||
constructor(client) {
|
||||
super({
|
||||
nodes: MUSIC.LAVALINK_NODES,
|
||||
sendToShard: (guildId, payload) => client.guilds.cache.get(guildId)?.shard?.send(payload),
|
||||
emitNewSongsOnly: false,
|
||||
queueOptions: {
|
||||
maxPreviousTracks: 30,
|
||||
},
|
||||
playerOptions: {
|
||||
defaultSearchPlatform: MUSIC.DEFAULT_SOURCE,
|
||||
onDisconnect: {
|
||||
autoReconnect: true,
|
||||
destroyPlayer: false,
|
||||
},
|
||||
},
|
||||
linksAllowed: true,
|
||||
linksBlacklist: ["porn"],
|
||||
linksWhitelist: [],
|
||||
});
|
||||
|
||||
this.nodeManager.on("connect", (node) => {
|
||||
client.logger.success(`Lavalink node ${node.id} connected!`);
|
||||
});
|
||||
|
||||
this.nodeManager.on("disconnect", (node, reason) => {
|
||||
client.logger.warn(`Lavalink node "${node.id}" disconnected. Reason: ${JSON.stringify(reason)}`);
|
||||
});
|
||||
|
||||
this.nodeManager.on("error", (node, error) => {
|
||||
client.logger.error(`Error occurred on Lavalink node "${node.id}": ${error.message}`);
|
||||
});
|
||||
|
||||
this.nodeManager.on("destroy", (node) => {
|
||||
client.logger.warn(`Lavalink node "${node.id}" destroyed`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Manager;
|
71
src/handlers/player.js
Normal file
71
src/handlers/player.js
Normal file
@ -0,0 +1,71 @@
|
||||
const { EMBED_COLORS, MUSIC } = require("@root/config");
|
||||
const { EmbedBuilder } = require("discord.js");
|
||||
|
||||
module.exports = {
|
||||
autoplayFunction: async (client, track, player) => {
|
||||
if (player.queue.tracks.length > 0) return;
|
||||
if (!track) return;
|
||||
|
||||
const channel = client.guilds.cache.get(player.guildId)?.channels.cache.get(player.textChannelId);
|
||||
|
||||
let url, source;
|
||||
|
||||
switch (track.info.sourceName) {
|
||||
case "spotify":
|
||||
url = `seed_tracks=${track.info.identifier ?? "11xbo8bGa5XTrXrGP77zwc"}&limit=20&min_popularity=30`;
|
||||
source = "sprec";
|
||||
break;
|
||||
|
||||
case "youtube":
|
||||
url = `https://youtube.com/watch?v=${track.info.identifier ?? "lpeuIu-ZYJY"}&list=RD${track.info.identifier ?? "lpeuIu-ZYJY"}`;
|
||||
source = "ytsearch";
|
||||
break;
|
||||
|
||||
case "jiosaavn":
|
||||
url = `${track.info.identifier ?? "Hvma-gqd"}`;
|
||||
source = "jsrec";
|
||||
break;
|
||||
|
||||
default:
|
||||
url = track.info.author;
|
||||
source = MUSIC.DEFAULT_SOURCE;
|
||||
break;
|
||||
}
|
||||
|
||||
const res = await player.search({ query: url, source: source }, track.requester);
|
||||
|
||||
if (!res || res.tracks.length === 0) {
|
||||
await channel.safeSend(
|
||||
{
|
||||
embeds: [new EmbedBuilder().setColor(EMBED_COLORS.WARNING).setDescription("> Autoplay, No results found")],
|
||||
},
|
||||
10
|
||||
);
|
||||
return player.destroy();
|
||||
}
|
||||
|
||||
for (let songs = 0; songs < 3; ) {
|
||||
const chosen = res.tracks[Math.floor(Math.random() * res.tracks.length)];
|
||||
|
||||
if (
|
||||
!player.queue.previous?.some((o) => o.info.identifier === chosen.info.identifier) &&
|
||||
!player.queue.tracks.some((o) => o.info.identifier === chosen.info.identifier)
|
||||
) {
|
||||
await player.queue.add(chosen);
|
||||
songs++;
|
||||
}
|
||||
}
|
||||
|
||||
if (player.queue.tracks.length === 0) {
|
||||
await channel?.safeSend(
|
||||
{
|
||||
embeds: [
|
||||
new EmbedBuilder().setColor(EMBED_COLORS.WARNING).setDescription("> Autoplay, No unique track found"),
|
||||
],
|
||||
},
|
||||
10
|
||||
);
|
||||
return player.destroy();
|
||||
}
|
||||
},
|
||||
};
|
@ -63,8 +63,8 @@ module.exports = class BotUtils {
|
||||
static get musicValidations() {
|
||||
return [
|
||||
{
|
||||
callback: ({ client, guildId }) => client.musicManager.players.resolve(guildId),
|
||||
message: "🚫 No music is being played!",
|
||||
callback: ({ client, guildId }) => client.musicManager.getPlayer(guildId),
|
||||
message: "🚫 I'm not in a voice channel.",
|
||||
},
|
||||
{
|
||||
callback: ({ member }) => member.voice?.channelId,
|
||||
@ -72,7 +72,7 @@ module.exports = class BotUtils {
|
||||
},
|
||||
{
|
||||
callback: ({ member, client, guildId }) =>
|
||||
member.voice?.channelId === client.musicManager.players.resolve(guildId)?.voice.channelId,
|
||||
member.voice?.channelId === client.musicManager.getPlayer(guildId)?.voiceChannelId,
|
||||
message: "🚫 You're not in the same voice channel.",
|
||||
},
|
||||
];
|
||||
|
@ -162,21 +162,43 @@ module.exports = class Utils {
|
||||
* @returns {string} - Formatted time string
|
||||
*/
|
||||
static formatTime(ms) {
|
||||
const minuteMs = 60 * 1000;
|
||||
const hourMs = 60 * minuteMs;
|
||||
const dayMs = 24 * hourMs;
|
||||
if (ms < minuteMs) {
|
||||
return `${ms / 1000}s`;
|
||||
} else if (ms < hourMs) {
|
||||
return `${Math.floor(ms / minuteMs)}m ${Math.floor(
|
||||
(ms % minuteMs) / 1000
|
||||
)}s`;
|
||||
} else if (ms < dayMs) {
|
||||
return `${Math.floor(ms / hourMs)}h ${Math.floor(
|
||||
(ms % hourMs) / minuteMs
|
||||
)}m`;
|
||||
} else {
|
||||
return `${Math.floor(ms / dayMs)}d ${Math.floor((ms % dayMs) / hourMs)}h`;
|
||||
}
|
||||
return ms < 1000
|
||||
? `${ms / 1000}s`
|
||||
: ["d", "h", "m", "s"]
|
||||
.map((unit, i) => {
|
||||
const value = [864e5, 36e5, 6e4, 1e3][i];
|
||||
const amount = Math.floor(ms / value);
|
||||
ms %= value;
|
||||
return amount ? `${amount}${unit}` : null;
|
||||
})
|
||||
.filter((x) => x !== null)
|
||||
.join(" ") || "0s";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a time string into milliseconds
|
||||
* @param {string} string - The time string (e.g., "1d", "2h", "3m", "4s")
|
||||
* @returns {number} - The time in milliseconds
|
||||
*/
|
||||
static parseTime(string) {
|
||||
const time = string.match(/([0-9]+[dhms])/g);
|
||||
if (!time) return 0;
|
||||
return time.reduce((ms, t) => {
|
||||
const unit = t[t.length - 1];
|
||||
const amount = Number(t.slice(0, -1));
|
||||
return ms + amount * { d: 864e5, h: 36e5, m: 6e4, s: 1e3 }[unit];
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates voice channel status
|
||||
* @param {string} channel - The voice channel ID
|
||||
* @param {string} status - The status to update
|
||||
* @param {object} client - The bot client
|
||||
*/
|
||||
static async setVoiceStatus(client, channelId, message) {
|
||||
const url = `/channels/${channelId}/voice-status`;
|
||||
const payload = { status: message };
|
||||
await client.rest.put(url, { body: payload }).catch(() => {});
|
||||
}
|
||||
};
|
||||
|
@ -44,14 +44,15 @@ module.exports = class Validator {
|
||||
|
||||
// Music
|
||||
if (config.MUSIC.ENABLED) {
|
||||
if (!process.env.SPOTIFY_CLIENT_ID || !process.env.SPOTIFY_CLIENT_SECRET) {
|
||||
warn("env: SPOTIFY_CLIENT_ID or SPOTIFY_CLIENT_SECRET are missing. Spotify music links won't work");
|
||||
}
|
||||
if (config.MUSIC.LAVALINK_NODES.length == 0) {
|
||||
warn("config.js: There must be at least one node for Lavalink");
|
||||
}
|
||||
if (!["ytsearch", "ytmsearch", "spsearch", "scsearch"].includes(config.MUSIC.DEFAULT_SOURCE)) {
|
||||
warn("config.js: MUSIC.DEFAULT_SOURCE must be either ytsearch, ytmsearch, spsearch or scsearch");
|
||||
if (
|
||||
!["ytsearch", "ytmsearch", "scsearch", "spsearch", "dzsearch", "jssearch"].includes(config.MUSIC.DEFAULT_SOURCE)
|
||||
) {
|
||||
warn(
|
||||
"config.js: MUSIC.DEFAULT_SOURCE must be either ytsearch, ytmsearch, scsearch, spsearch, dzsearch or jssearch"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ const { recursiveReadDirSync } = require("../helpers/Utils");
|
||||
const { validateCommand, validateContext } = require("../helpers/Validator");
|
||||
const { schemas } = require("@src/database/mongoose");
|
||||
const CommandCategory = require("./CommandCategory");
|
||||
const lavaclient = require("../handlers/lavaclient");
|
||||
const Manager = require("../handlers/manager");
|
||||
const giveawaysHandler = require("../handlers/giveaway");
|
||||
const { DiscordTogether } = require("discord-together");
|
||||
|
||||
@ -65,7 +65,7 @@ module.exports = class BotClient extends Client {
|
||||
: undefined;
|
||||
|
||||
// Music Player
|
||||
if (this.config.MUSIC.ENABLED) this.musicManager = lavaclient(this);
|
||||
if (this.config.MUSIC.ENABLED) this.musicManager = new Manager(this);
|
||||
|
||||
// Giveaways
|
||||
if (this.config.GIVEAWAYS.ENABLED) this.giveawaysManager = giveawaysHandler(this);
|
||||
@ -76,6 +76,9 @@ module.exports = class BotClient extends Client {
|
||||
// Database
|
||||
this.database = schemas;
|
||||
|
||||
// Utils
|
||||
this.utils = require("../helpers/Utils");
|
||||
|
||||
// Discord Together
|
||||
this.discordTogether = new DiscordTogether(this);
|
||||
}
|
||||
@ -92,18 +95,23 @@ module.exports = class BotClient extends Client {
|
||||
|
||||
recursiveReadDirSync(directory).forEach((filePath) => {
|
||||
const file = path.basename(filePath);
|
||||
const dir = path.basename(path.dirname(filePath));
|
||||
try {
|
||||
const eventName = path.basename(file, ".js");
|
||||
const event = require(filePath);
|
||||
|
||||
this.on(eventName, event.bind(null, this));
|
||||
if (dir === "player") {
|
||||
this.musicManager.on(eventName, event.bind(null, this));
|
||||
} else {
|
||||
this.on(eventName, event.bind(null, this));
|
||||
}
|
||||
clientEvents.push([file, "✓"]);
|
||||
|
||||
delete require.cache[require.resolve(filePath)];
|
||||
success += 1;
|
||||
} catch (ex) {
|
||||
failed += 1;
|
||||
this.logger.error(`loadEvent - ${file}`, ex);
|
||||
this.logger.error(`Failed to load event - ${file}`, ex);
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user