Skip to content
This repository was archived by the owner on Jan 12, 2022. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Music bot that uses Lavalink for its audio player.",
"main": "index.js",
"scripts": {
"start": "node ."
"start": "node .",
"regscmd": "node scripts/registerslashcommand"
},
"repository": {
"type": "git",
Expand Down
6 changes: 6 additions & 0 deletions scripts/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# the bot token
TOKEN=AAAAAAAAAAAAAAa
# the bot id
ID=000000000000
# guild id that used to develop the bot
DEV_GUILD=1111111111111111
42 changes: 42 additions & 0 deletions scripts/registerslashcommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { Constants } = require("discord.js");
const { readdirSync } = require("fs");
const { resolve, join } = require("path");
const petitio = require("petitio");

require("dotenv").config({
path: resolve(__dirname, ".env")
});

process.argv[2] === "dev" ? console.log(`Running with dev arg. commands will only registered to dev guild (${process.env.DEV_GUILD})`) : console.log("Registering commands globally");

const baseURL = "https://discord.com/api/v9";

const commandsDir = resolve("src", "commands");
const commands = readdirSync(commandsDir)
.map(cmdFile => require(resolve(commandsDir, cmdFile)))
.map(({ name, description, options }) => ({
name,
description,
options: Object.entries(options ?? {})
.map(([name, { description, type, required }]) => ({
name,
description,
type: Constants.ApplicationCommandOptionTypes[type],
required
}))
}));

(async () => {
const res = await petitio(baseURL, "PUT")
.body(commands)
.header("Authorization", `Bot ${process.env.TOKEN}`)
.path(join("applications", process.env.ID, ...(process.argv[2] === "dev" ? ["guilds", process.env.DEV_GUILD] : []), "commands"))
.send();

if (!(res.statusCode >= 200 && res.statusCode < 300)) {
console.log(res.json());
return;
}

console.log(res.json().map((x, i) => `${++i}. ${x.name} registered`).join("\n"));
})();
21 changes: 12 additions & 9 deletions src/commands/bassboost.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ module.exports = {
name: "bassboost",
description: "Set bassboost for player",
aliases: ["bb"],
options: {
value: {
description: "Basboost value; 0 to disable",
type: "INTEGER",
}
},
exec: async (ctx) => {
const { music, args } = ctx;
const { music, options } = ctx;
if (!music.player?.track) return ctx.respond({
embeds: [util.embed().setDescription("❌ | Currently not playing anything.")]
});
Expand All @@ -17,16 +23,13 @@ module.exports = {
embeds: [util.embed().setDescription(`❌ | You must be on ${ctx.guild.me.voice.channel} to use this command.`)]
});

if (!args[0]) {
if (!options.value) {
ctx.respond(util.embed().setDescription(`${music.filters.bassboost ? `✅ | BassBoost **${music.bassboost * 100}%**` : "❌ | BassBoost **off**"}`));
} else if (args[0].toLowerCase() == "off") {
music.setBassboost(0);
ctx.react("✅").catch(e => e);
} else {
if (isNaN(args[0])) return ctx.respond(util.embed().setDescription("❌ | Specify a number"));
if (args[0] < 1 || args[0] > 100) return ctx.respond(util.embed().setDescription("❌ | You can only set the bassboost from 1 to 100."));
music.setBassboost(parseInt(args[0]));
ctx.respond(util.embed().setDescription(`✅ | BassBoost set to **${music.bassboost * 100}%**`));
if (isNaN(options.value)) return ctx.respond(util.embed().setDescription("❌ | Specify a number"));
if (options.value < 1 || options.value > 100) return ctx.respond(util.embed().setDescription("❌ | You can only set the bassboost from 1 to 100."));
music.setBassboost(parseInt(options.value));
ctx.respond(util.embed().setDescription(`✅ | BassBoost set to **${ music.bassboost ? "off" : `${music.bassboost * 100}%` }**`));
}
}
};
20 changes: 17 additions & 3 deletions src/commands/eval.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,25 @@ module.exports = {
name: "eval",
description: "Evaluate JS code",
aliases: ["e"],
options: {
code: {
description: "Code to eval",
type: "STRING",
required: true
},
async: {
description: "Async eval",
type: "BOOLEAN",
},
silent: {
description: "Dont send output",
type: "BOOLEAN",
}
},
exec: async (ctx) => {
if (ctx.author.id !== process.env.OWNER_ID) return;
const isAsync = ctx.args.includes("--async");
const isSilent = ctx.args.includes("--silent");
const code = ctx.args.filter(e => !/^--(async|silent)$/.test(e)).join(" ");
console.log(ctx.options);
const { code, async: isAsync, silent: isSilent } = ctx.options;
try {
let result = eval(isAsync ? `(async()=>{${code}})()` : code);
let isResultPromise = false;
Expand Down
16 changes: 13 additions & 3 deletions src/commands/move.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ module.exports = {
name: "move",
description: "Move track position in queue",
aliases: ["mv"],
options: {
from: {
description: "Number of the song to move",
type: "INTEGER",
required: true
},
to: {
description: "The new position",
type: "INTEGER",
required: true
}
},
exec: async (ctx) => {
const { music, args } = ctx;
const from = args[0] ? parseInt(args[0], 10) : null;
const to = args[1] ? parseInt(args[1], 10) : null;
const { music, options: { from, to } } = ctx;
if (!music.player?.track) return ctx.respond({
embeds: [util.embed().setDescription("❌ | Currently not playing anything.")]
});
Expand Down
21 changes: 13 additions & 8 deletions src/commands/play.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
const util = require("../util");

const getAttachmentURL = ctx => ctx.attachments.first()?.url;
//const getAttachmentURL = ctx => ctx.attachments.first()?.url;

module.exports = {
name: "play",
description: "Add song to queue and play it",
description: "Adds song to queue and play it",
aliases: ["p"],
options: {
query: {
description: "Song title/url",
type: "STRING",
required: true
}
},
exec: async (ctx) => {
const { args, music } = ctx;
const { music, options: { query } } = ctx;
if (!ctx.member.voice.channel)
return ctx.respond({
embeds: [util.embed().setDescription("❌ | You must be on a voice channel.")]
Expand All @@ -28,7 +35,6 @@ module.exports = {
embeds: [util.embed().setDescription("❌ | Lavalink node is not connected yet.")]
});

const query = args.join(" ") || getAttachmentURL(ctx.message);
if (!query) return ctx.respond({
embeds: [util.embed().setDescription("❌ | Missing args.")]
});
Expand All @@ -51,10 +57,9 @@ module.exports = {
const track = tracks[0];
track.requester = ctx.author;
music.queue.push(track);
if (music.player?.track)
ctx.respond({
embeds: [util.embed().setDescription(`✅ | **${track.info.title}** added to the queue.`)]
});
ctx.respond({
embeds: [util.embed().setDescription(`✅ | **${track.info.title}** added to the queue.`)]
});
}
if (!music.player) await music.join(ctx.member.voice.channel);
if (!music.player.track) await music.start();
Expand Down
13 changes: 10 additions & 3 deletions src/commands/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ module.exports = {
name: "remove",
description: "Remove track from queue",
aliases: ["rm"],
options: {
toremove: {
description: "Number of the song to remove",
type: "INTEGER",
required: true
}
},
exec: async (ctx) => {
const { music, args } = ctx;
const { music, options: { toremove: toRemove } } = ctx;
if (!music.player?.track) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Currently not playing anything.")] });
if (!music.queue.length) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Queue is empty.")] });

Expand All @@ -14,9 +21,9 @@ module.exports = {
if (ctx.guild.me.voice.channel && !ctx.guild.me.voice.channel.equals(ctx.member.voice.channel))
return ctx.respond({ embeds: [util.embed().setDescription(`❌ | You must be on ${ctx.guild.me.voice.channel} to use this command.`)] });

if (!args[0]) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Missing args.")] });
if (!toRemove) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Missing args.")] });

let iToRemove = parseInt(args[0], 10);
let iToRemove = parseInt(toRemove, 10);
if (isNaN(iToRemove) || iToRemove < 1 || iToRemove > music.queue.length)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | Invalid number to remove.")] });

Expand Down
10 changes: 8 additions & 2 deletions src/commands/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ const emojiNumbers = ["1️⃣","2️⃣","3️⃣","4️⃣","5️⃣","6️⃣
module.exports = {
name: "search",
description: "Search song to play",
options: {
query: {
description: "Song title",
type: "STRING",
required: true
}
},
exec: async (ctx) => {
const { music, args } = ctx;
const { music, options: { query } } = ctx;
if (!ctx.member.voice.channel)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | You must be on a voice channel.")] });
if (ctx.guild.me.voice.channel && !ctx.guild.me.voice.channel.equals(ctx.member.voice.channel))
Expand All @@ -20,7 +27,6 @@ module.exports = {
if (music.node?.state !== 1)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | Lavalink node is not connected yet.")] });

const query = args.join(" ");
if (!query) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Missing args.")] });

try {
Expand Down
16 changes: 11 additions & 5 deletions src/commands/seek.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ const durationPattern = /^[0-5]?[0-9](:[0-5][0-9]){1,2}$/;
module.exports = {
name: "seek",
description: "Seeks to specified timestamp",
options: {
toduration: {
description: "Duration with format mm:ss",
type: "INTEGER",
required: true
}
},
exec: async (ctx) => {
const { music, args } = ctx;
const { music, options: { toduration: toDuration } } = ctx;
if (!music.player?.track) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Currently not playing anything.")] });
if (!ctx.member.voice.channel)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | You must be on a voice channel.")] });
Expand All @@ -16,13 +23,12 @@ module.exports = {
if (!music.current.info.isSeekable)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | Current track isn't seekable.")] });

const duration = args[0];
if (!duration)
if (!toDuration)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | You must provide duration to seek. Valid duration e.g. `1:34`.")] });
if (!durationPattern.test(duration))
if (!durationPattern.test(toDuration))
return ctx.respond({ embeds: [util.embed().setDescription("❌ | You provided an invalid duration. Valid duration e.g. `1:34`.")] });

const durationMs = util.durationToMillis(duration);
const durationMs = util.durationToMillis(toDuration);
if (durationMs > music.current.info.length)
return ctx.respond({ embeds: [util.embed().setDescription("❌ | The duration you provide exceeds the duration of the current track.")] });

Expand Down
9 changes: 7 additions & 2 deletions src/commands/volume.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ module.exports = {
name: "volume",
description: "Check and set volume",
aliases: ["vol"],
options: {
newvolume: {
description: "New volume to set",
type: "INTEGER",
}
},
exec: async (ctx) => {
const { music, args } = ctx;
const newVolume = parseInt(args[0], 10);
const { music, options: { newvolume: newVolume } } = ctx;
if (!music.player?.track) return ctx.respond({ embeds: [util.embed().setDescription("❌ | Currently not playing anything.")] });
try {
if (isNaN(newVolume)) {
Expand Down
23 changes: 23 additions & 0 deletions src/listeners/interactionCreate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const CommandContext = require("../structures/CommandContext");
const Util = require("../util");

module.exports = {
name: "interactionCreate",
exec: async (client, interaction) => {
if (!interaction.isCommand()) return;
const command = client.commands.get(interaction.commandName);

if (command) {
const options = {};
for (const name in command.options ?? {}) {
options[name] = Util.getOptionValue(interaction.options.data.find(x => x.name === name));
}
try {
await interaction.deferReply();
await command.exec(new CommandContext(command, interaction, options));
} catch (e) {
console.error(e);
}
}
}
};
12 changes: 9 additions & 3 deletions src/listeners/messageCreate.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const CommandContext = require("../structures/CommandContext");
const Util = require("../util");

module.exports = {
name: "messageCreate",
Expand All @@ -9,12 +10,17 @@ module.exports = {
const prefix = msg.content.toLowerCase().startsWith(client.prefix) ? client.prefix : `<@!${client.user.id}>`;
if (!msg.content.toLowerCase().startsWith(prefix)) return;

const args = msg.content.slice(prefix.length).trim().split(/ +/g);
const commandName = args.shift().toLowerCase();
let [commandName, ...args] = msg.content.slice(prefix.length).trim().split(/ +/g);
args = args.join(" ").trim().split(/; +/g);
const command = client.commands.get(commandName) || client.commands.find(c => c.aliases && c.aliases.includes(commandName));

if (command) {
const options = {};
for (const [name, { type }] of Object.entries(command.options ?? {})) {
options[name] = Util.parseArg(msg.guild, type, args.shift());
}
try {
await command.exec(new CommandContext(command, msg, args));
await command.exec(new CommandContext(command, msg, options));
} catch (e) {
console.error(e);
}
Expand Down
Loading