Class commands, improved sharding, and many other changes (#88)
* Load commands recursively * Sort commands * Missed a couple of spots * missed even more spots apparently * Ported commands in "fun" category to new class-based format, added babel eslint plugin * Ported general commands, removed old/unneeded stuff, replaced moment with day, many more fixes I lost track of * Missed a spot * Removed unnecessary abort-controller package, add deprecation warning for mongo database * Added imagereload, clarified premature end message * Fixed docker-compose path issue, added total bot uptime to stats, more fixes for various parts * Converted image commands into classes, fixed reload, ignore another WS event, cleaned up command handler and image runner * Converted music/soundboard commands to class format * Cleanup unnecessary logs * awful tag command class port * I literally somehow just learned that you can leave out the constructor in classes * Pass client directly to commands/events, cleaned up command handler * Migrated bot to eris-sharder, fixed some error handling stuff * Remove unused modules * Fixed type returning * Switched back to Eris stable * Some fixes and cleanup * might wanna correct this * Implement image command ratelimiting * Added Bot token prefix, added imagestats, added running endpoint to API
This commit is contained in:
parent
ff8a24d0e8
commit
40223ec8b5
291 changed files with 5296 additions and 5171 deletions
|
@ -3,12 +3,19 @@
|
|||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:promise/recommended"],
|
||||
"extends": ["eslint:recommended"],
|
||||
"parser": "@babel/eslint-parser",
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2019
|
||||
"ecmaVersion": 12,
|
||||
"requireConfigFile": false,
|
||||
"babelOptions": {
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugins": ["promise"],
|
||||
"plugins": ["@babel"],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"indent": [
|
||||
|
|
63
api/index.js
63
api/index.js
|
@ -30,19 +30,16 @@ const acceptJob = async (uuid, sock) => {
|
|||
msg: jobs[uuid].msg,
|
||||
num: jobs[uuid].num
|
||||
}, sock);
|
||||
jobAmount--;
|
||||
if (queue.length > 0) {
|
||||
acceptJob(queue[0], sock);
|
||||
}
|
||||
log(`Job ${uuid} has finished`);
|
||||
} catch (err) {
|
||||
console.error(`Error on job ${uuid}:`, err);
|
||||
delete jobs[uuid];
|
||||
sock.write(Buffer.concat([Buffer.from([0x2]), Buffer.from(uuid), Buffer.from(err.message)]));
|
||||
} finally {
|
||||
jobAmount--;
|
||||
if (queue.length > 0) {
|
||||
acceptJob(queue[0], sock);
|
||||
}
|
||||
delete jobs[uuid];
|
||||
sock.write(Buffer.concat([Buffer.from([0x2]), Buffer.from(uuid), Buffer.from(err.toString())]));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -55,6 +52,22 @@ const httpServer = http.createServer((req, res) => {
|
|||
if (reqUrl.pathname === "/status") {
|
||||
log(`Sending server status to ${req.socket.remoteAddress}:${req.socket.remotePort} via HTTP`);
|
||||
return res.end(Buffer.from((MAX_JOBS - jobAmount).toString()));
|
||||
} else if (reqUrl.pathname === "/running") {
|
||||
log(`Sending currently running jobs to ${req.socket.remoteAddress}:${req.socket.remotePort} via HTTP`);
|
||||
const keys = Object.keys(jobs);
|
||||
const newObject = { queued: queue.length, runningJobs: jobAmount, max: MAX_JOBS };
|
||||
for (const key of keys) {
|
||||
const validKeys = Object.keys(jobs[key]).filter((value) => value !== "addr" && value !== "port" && value !== "data" && value !== "ext");
|
||||
newObject[key] = {};
|
||||
for (const validKey of validKeys) {
|
||||
if (validKey === "msg") {
|
||||
newObject[key][validKey] = JSON.parse(jobs[key][validKey]);
|
||||
} else {
|
||||
newObject[key][validKey] = jobs[key][validKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.end(JSON.stringify(newObject));
|
||||
} else if (reqUrl.pathname === "/image") {
|
||||
if (!reqUrl.searchParams.has("id")) {
|
||||
res.statusCode = 400;
|
||||
|
@ -134,7 +147,7 @@ const server = net.createServer((sock) => { // Create a TCP socket/server to lis
|
|||
for (const job of Object.keys(jobs)) {
|
||||
if (jobs[job].addr === sock.remoteAddress && jobs[job].port === sock.remotePort) {
|
||||
delete jobs[job];
|
||||
sock.write(Buffer.concat([Buffer.from([0x2]), Buffer.from(job), Buffer.from("Job ended prematurely")]));
|
||||
sock.write(Buffer.concat([Buffer.from([0x2]), Buffer.from(job), Buffer.from("Job ended prematurely (not really an error; just run your image job again)")]));
|
||||
}
|
||||
}
|
||||
process.exit(0);
|
||||
|
@ -149,28 +162,22 @@ server.listen(8080, () => {
|
|||
log("TCP listening on port 8080");
|
||||
});
|
||||
|
||||
const runJob = (job, sock) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
log(`Job ${job.uuid} starting...`, job.num);
|
||||
const runJob = async (job, sock) => {
|
||||
log(`Job ${job.uuid} starting...`, job.num);
|
||||
|
||||
const object = JSON.parse(job.msg);
|
||||
// If the image has a path, it must also have a type
|
||||
if (object.path && !object.type) {
|
||||
reject(new TypeError("Unknown image type"));
|
||||
}
|
||||
const object = JSON.parse(job.msg);
|
||||
// If the image has a path, it must also have a type
|
||||
if (object.path && !object.type) {
|
||||
throw new TypeError("Unknown image type");
|
||||
}
|
||||
|
||||
log(`Job ${job.uuid} started`, job.num);
|
||||
run(object).then((data) => {
|
||||
log(`Sending result of job ${job.uuid} back to the bot`, job.num);
|
||||
jobs[job.uuid].data = data.buffer;
|
||||
jobs[job.uuid].ext = data.fileExtension;
|
||||
sock.write(Buffer.concat([Buffer.from([0x1]), Buffer.from(job.uuid)]), (e) => {
|
||||
if (e) return reject(e);
|
||||
return resolve();
|
||||
});
|
||||
return;
|
||||
}).catch(e => {
|
||||
reject(e);
|
||||
});
|
||||
log(`Job ${job.uuid} started`, job.num);
|
||||
const data = await run(object).catch(e => { throw e; });
|
||||
log(`Sending result of job ${job.uuid} back to the bot`, job.num);
|
||||
jobs[job.uuid].data = data.buffer;
|
||||
jobs[job.uuid].ext = data.fileExtension;
|
||||
sock.write(Buffer.concat([Buffer.from([0x1]), Buffer.from(job.uuid)]), (e) => {
|
||||
if (e) throw e;
|
||||
});
|
||||
return;
|
||||
};
|
98
app.js
98
app.js
|
@ -1,80 +1,34 @@
|
|||
if (process.platform === "win32") console.log("\x1b[1m\x1b[31m\x1b[40m" + `WIN32 IS NOT OFFICIALLY SUPPORTED!
|
||||
if (process.platform === "win32") console.error("\x1b[1m\x1b[31m\x1b[40m" + `WIN32 IS NOT OFFICIALLY SUPPORTED!
|
||||
Although there's a (very) slim chance of it working, multiple aspects of the bot are built with UNIX-like systems in mind and could break on Win32-based systems. If you want to run the bot on Windows, using Windows Subsystem for Linux is highly recommended.
|
||||
The bot will continue to run past this message, but keep in mind that it could break at any time. Continue running at your own risk; alternatively, stop the bot using Ctrl+C and install WSL.` + "\x1b[0m");
|
||||
|
||||
// load config from .env file
|
||||
require("dotenv").config();
|
||||
|
||||
// turn fs.readdir into a promise
|
||||
const readdir = require("util").promisify(require("fs").readdir);
|
||||
// fancy loggings
|
||||
const logger = require("./utils/logger.js");
|
||||
// start the client
|
||||
const client = require("./utils/client.js");
|
||||
// initialize command loader
|
||||
const handler = require("./utils/handler.js");
|
||||
const sound = require("./utils/soundplayer.js");
|
||||
const image = require("./utils/image.js");
|
||||
const { Master } = require("eris-sharder");
|
||||
|
||||
// registers stuff and connects the bot
|
||||
async function init() {
|
||||
logger.log("info", "Starting esmBot...");
|
||||
// register commands and their info
|
||||
const commands = await readdir("./commands/");
|
||||
const soundStatus = await sound.checkStatus();
|
||||
logger.log("info", `Attempting to load ${commands.length} commands...`);
|
||||
for (const commandFile of commands) {
|
||||
logger.log("info", `Loading command ${commandFile}...`);
|
||||
try {
|
||||
await handler.load(commandFile, soundStatus);
|
||||
} catch (e) {
|
||||
logger.error(`Failed to register command ${commandFile.split(".")[0]}: ${e}`);
|
||||
}
|
||||
new Master(`Bot ${process.env.TOKEN}`, "/shard.js", {
|
||||
name: "esmBot",
|
||||
clientOptions: {
|
||||
disableEvents: {
|
||||
CHANNEL_DELETE: true,
|
||||
CHANNEL_UPDATE: true,
|
||||
GUILD_BAN_REMOVE: true,
|
||||
GUILD_MEMBER_ADD: true,
|
||||
GUILD_MEMBER_REMOVE: true,
|
||||
GUILD_MEMBER_UPDATE: true,
|
||||
GUILD_ROLE_CREATE: true,
|
||||
GUILD_ROLE_DELETE: true,
|
||||
GUILD_ROLE_UPDATE: true,
|
||||
TYPING_START: true,
|
||||
MESSAGE_DELETE_BULK: true
|
||||
},
|
||||
allowedMentions: {
|
||||
everyone: false,
|
||||
roles: false,
|
||||
users: true,
|
||||
repliedUser: true
|
||||
},
|
||||
guildSubscriptions: false
|
||||
}
|
||||
|
||||
// register events
|
||||
const events = await readdir("./events/");
|
||||
logger.log("info", `Attempting to load ${events.length} events...`);
|
||||
for (const file of events) {
|
||||
logger.log("info", `Loading event ${file}...`);
|
||||
const eventName = file.split(".")[0];
|
||||
const event = require(`./events/${file}`);
|
||||
client.on(eventName, event);
|
||||
}
|
||||
|
||||
// connect to image api if enabled
|
||||
if (process.env.API === "true") {
|
||||
for (const server of image.servers) {
|
||||
try {
|
||||
await image.connect(server);
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// login
|
||||
client.connect();
|
||||
|
||||
// post to DBL
|
||||
if (process.env.NODE_ENV === "production" && process.env.DBL !== "") {
|
||||
require("./utils/dbl.js");
|
||||
}
|
||||
|
||||
// handle ctrl+c and pm2 stop
|
||||
process.on("SIGINT", () => {
|
||||
logger.log("info", "SIGINT detected, shutting down...");
|
||||
client.editStatus("dnd", {
|
||||
name: "Restarting/shutting down..."
|
||||
});
|
||||
for (const command of commands) {
|
||||
handler.unload(command);
|
||||
}
|
||||
client.disconnect();
|
||||
require("./utils/database.js").stop();
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
// launch the bot
|
||||
init();
|
||||
});
|
19
classes/command.js
Normal file
19
classes/command.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
class Command {
|
||||
constructor(client, message, args, content) {
|
||||
this.client = client;
|
||||
this.message = message;
|
||||
this.args = args;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
async run() {
|
||||
return "It works!";
|
||||
}
|
||||
|
||||
static description = "No description found";
|
||||
static aliases = [];
|
||||
static arguments = [];
|
||||
static requires = [];
|
||||
}
|
||||
|
||||
module.exports = Command;
|
125
classes/imageCommand.js
Normal file
125
classes/imageCommand.js
Normal file
|
@ -0,0 +1,125 @@
|
|||
const Command = require("./command.js");
|
||||
const magick = require("../utils/image.js");
|
||||
const imageDetect = require("../utils/imagedetect.js");
|
||||
const collections = require("../utils/collections.js");
|
||||
|
||||
class ImageCommand extends Command {
|
||||
/*this.embed = {
|
||||
"title": "Your image is being generated! (PRELIMINARY EMBED)",
|
||||
"description": "The current progress is outlined below:",
|
||||
"color": 16711680,
|
||||
"footer": {
|
||||
"text": "Step 2/3"
|
||||
},
|
||||
"author": {
|
||||
"name": "Processing...",
|
||||
"icon_url": "https://cdn.discordapp.com/avatars/429305856241172480/a20f739886ae47cfb10fa069416e8ed3.jpg"
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"name": "Downloading...",
|
||||
"value": "✅ Done!"
|
||||
},
|
||||
{
|
||||
"name": "Processing...",
|
||||
"value": "<a:processing:818243325891051581> In progress"
|
||||
},
|
||||
{
|
||||
"name": "Uploading...",
|
||||
"value": "<a:processing:818243325891051581> Waiting for previous steps to complete"
|
||||
}
|
||||
]
|
||||
};*/
|
||||
|
||||
criteria() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async run() {
|
||||
// check if this command has already been run in this channel with the same arguments, and we are awaiting its result
|
||||
// if so, don't re-run it
|
||||
if (collections.runningCommands.has(this.message.author.id) && (new Date(collections.runningCommands.get(this.message.author.id)) - new Date(this.message.createdAt)) < 5000) {
|
||||
return `${this.message.author.mention}, please slow down a bit.`;
|
||||
}
|
||||
// before awaiting the command result, add this command to the set of running commands
|
||||
collections.runningCommands.set(this.message.author.id, this.message.createdAt);
|
||||
|
||||
const magickParams = {
|
||||
cmd: this.constructor.command
|
||||
};
|
||||
|
||||
if (this.constructor.requiresImage) {
|
||||
try {
|
||||
const image = await imageDetect(this.client, this.message);
|
||||
if (image === undefined) {
|
||||
collections.runningCommands.delete(this.message.author.id);
|
||||
return `${this.message.author.mention}, ${this.constructor.noImage}`;
|
||||
}
|
||||
magickParams.path = image.path;
|
||||
magickParams.type = image.type;
|
||||
magickParams.url = image.url; // technically not required but can be useful for text filtering
|
||||
magickParams.delay = image.delay;
|
||||
if (this.constructor.requiresGIF) magickParams.onlyGIF = true;
|
||||
} catch (e) {
|
||||
collections.runningCommands.delete(this.message.author.id);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.constructor.requiresText) {
|
||||
if (this.args.length === 0 || !this.criteria(this.args)) {
|
||||
collections.runningCommands.delete(this.message.author.id);
|
||||
return `${this.message.author.mention}, ${this.constructor.noText}`;
|
||||
}
|
||||
}
|
||||
|
||||
switch (typeof this.params) {
|
||||
case "function":
|
||||
Object.assign(magickParams, this.params(this.args, magickParams.url));
|
||||
break;
|
||||
case "object":
|
||||
Object.assign(magickParams, this.params);
|
||||
break;
|
||||
}
|
||||
|
||||
let status;
|
||||
if (magickParams.type === "image/gif") {
|
||||
status = await this.processMessage(this.message);
|
||||
} else {
|
||||
this.message.channel.sendTyping();
|
||||
}
|
||||
|
||||
try {
|
||||
const { buffer, type } = await magick.run(magickParams).catch(e => {
|
||||
throw e;
|
||||
});
|
||||
if (status && status.channel.messages.get(status.id)) await status.delete();
|
||||
if (type === "nogif" && this.constructor.requiresGIF) return `${this.message.author.mention}, that isn't a GIF!`;
|
||||
return {
|
||||
file: buffer,
|
||||
name: `${this.constructor.command}.${type}`
|
||||
};
|
||||
} catch (e) {
|
||||
if (status && status.channel.messages.get(status.id)) await status.delete();
|
||||
if (e.toString().includes("Not connected to image server")) return `${this.message.author.mention}, I'm still trying to connect to the image servers. Please wait a little bit.`;
|
||||
throw e;
|
||||
} finally {
|
||||
collections.runningCommands.delete(this.message.author.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
processMessage(message) {
|
||||
return message.channel.createMessage(`${process.env.PROCESSING_EMOJI || "<a:processing:479351417102925854>"} Processing... This might take a while`);
|
||||
}
|
||||
|
||||
static requiresImage = true;
|
||||
static requiresText = false;
|
||||
static requiresGIF = false;
|
||||
static noImage = "you need to provide an image!";
|
||||
static noText = "you need to provide some text!";
|
||||
static command = "";
|
||||
}
|
||||
|
||||
module.exports = ImageCommand;
|
13
classes/musicCommand.js
Normal file
13
classes/musicCommand.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
const Command = require("./command.js");
|
||||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
class MusicCommand extends Command {
|
||||
constructor(client, message, args, content) {
|
||||
super(client, message, args, content);
|
||||
this.connection = soundPlayer.players.get(message.channel.guild.id);
|
||||
}
|
||||
|
||||
static requires = ["sound"];
|
||||
}
|
||||
|
||||
module.exports = MusicCommand;
|
|
@ -1,32 +0,0 @@
|
|||
const { random } = require("../utils/misc.js");
|
||||
const responses = [
|
||||
"It is certain",
|
||||
"It is decidedly so",
|
||||
"Without a doubt",
|
||||
"Yes, definitely",
|
||||
"You may rely on it",
|
||||
"As I see it, yes",
|
||||
"Most likely",
|
||||
"Outlook good",
|
||||
"Yes",
|
||||
"Signs point to yes",
|
||||
"Reply hazy, try again",
|
||||
"Ask again later",
|
||||
"Better not tell you now",
|
||||
"Cannot predict now",
|
||||
"Concentrate and ask again",
|
||||
"Don't count on it",
|
||||
"My reply is no",
|
||||
"My sources say no",
|
||||
"Outlook not so good",
|
||||
"Very doubtful"
|
||||
];
|
||||
|
||||
exports.run = async () => {
|
||||
return `🎱 ${random(responses)}`;
|
||||
};
|
||||
|
||||
exports.aliases = ["magicball", "magikball", "magic8ball", "magik8ball", "eightball"];
|
||||
exports.category = 4;
|
||||
exports.help = "Asks the magic 8-ball a question";
|
||||
exports.params = "{text}";
|
|
@ -1,22 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a 9GAG watermark!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "watermark",
|
||||
path: image.path,
|
||||
water: "./assets/images/9gag.png",
|
||||
gravity: 6,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `9gag.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["ninegag", "gag"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds the 9gag watermark to an image";
|
|
@ -1,22 +0,0 @@
|
|||
const client = require("../utils/client.js");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (message.mentions[0] !== undefined) {
|
||||
return message.mentions[0].dynamicAvatarURL(null, 1024);
|
||||
} else if (client.users.get(args[0]) !== undefined) {
|
||||
return client.users.get(args[0]).dynamicAvatarURL(null, 1024);
|
||||
} else if (args.join(" ") !== "" && message.channel.guild) {
|
||||
const userRegex = new RegExp(args.join("|"), "i");
|
||||
const member = message.channel.guild.members.find(element => {
|
||||
return userRegex.test(element.nick) ? userRegex.test(element.nick) : userRegex.test(element.username);
|
||||
});
|
||||
return member ? member.user.dynamicAvatarURL(null, 1024) : message.author.dynamicAvatarURL(null, 1024);
|
||||
} else {
|
||||
return message.author.dynamicAvatarURL(null, 1024);
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["pfp", "ava"];
|
||||
exports.category = 1;
|
||||
exports.help = "Gets a user's avatar";
|
||||
exports.params = "{mention/id}";
|
|
@ -1,23 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a Bandicam watermark!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "watermark",
|
||||
path: image.path,
|
||||
water: "./assets/images/bandicam.png",
|
||||
gravity: 2,
|
||||
resize: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `bandicam.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["bandi"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds the Bandicam watermark to an image";
|
|
@ -1,19 +0,0 @@
|
|||
const fetch = require("node-fetch");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const imageData = await fetch("http://shibe.online/api/birds");
|
||||
const json = await imageData.json();
|
||||
return {
|
||||
embed: {
|
||||
color: 16711680,
|
||||
image: {
|
||||
url: json[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["birb", "birds", "birbs"];
|
||||
exports.category = 4;
|
||||
exports.help = "Gets a random bird picture";
|
|
@ -1,20 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to blur!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "blur",
|
||||
path: image.path,
|
||||
sharp: false,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `blur.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.category = 5;
|
||||
exports.help = "Blurs an image";
|
|
@ -1,20 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to make blurple!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "blurple",
|
||||
path: image.path,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `blurple.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["blurp"];
|
||||
exports.category = 5;
|
||||
exports.help = "Turns an image blurple";
|
|
@ -1,10 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/boi.ogg", message);
|
||||
};
|
||||
|
||||
exports.aliases = ["boy", "neutron", "hugh"];
|
||||
exports.category = 6;
|
||||
exports.help = "Plays the \"boi\" sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,10 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/boom.ogg", message);
|
||||
};
|
||||
|
||||
exports.aliases = ["thud", "vine"];
|
||||
exports.category = 6;
|
||||
exports.help = "Plays the Vine boom sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,10 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/bruh.ogg", message);
|
||||
};
|
||||
|
||||
exports.aliases = ["bro"];
|
||||
exports.category = 6;
|
||||
exports.help = "Plays the \"bruh\" sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,24 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image/GIF to add a caption!`;
|
||||
const newArgs = args.filter(item => !item.includes(image.url) );
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide some text to add a caption!`;
|
||||
const processMessage = await message.channel.createMessage(`${process.env.PROCESSING_EMOJI || "<a:processing:479351417102925854>"} Processing... This might take a while`);
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "caption",
|
||||
path: image.path,
|
||||
caption: newArgs.join(" ").replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%"),
|
||||
type: image.type
|
||||
});
|
||||
if (processMessage.channel.messages.get(processMessage.id)) await processMessage.delete();
|
||||
return {
|
||||
file: buffer,
|
||||
name: `caption.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["gifc", "gcaption", "ifcaption", "ifunnycaption"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds a caption to an image/GIF";
|
|
@ -1,24 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
const words = ["me irl", "dank", "follow my second account @esmBot_", "2016", "meme", "wholesome", "reddit", "instagram", "twitter", "facebook", "fortnite", "minecraft", "relatable", "gold", "funny", "template", "hilarious", "memes", "deep fried", "2020", "leafy", "pewdiepie"];
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image/GIF to add a caption!`;
|
||||
const newArgs = args.filter(item => !item.includes(image.url) );
|
||||
const processMessage = await message.channel.createMessage(`${process.env.PROCESSING_EMOJI || "<a:processing:479351417102925854>"} Processing... This might take a while`);
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "captionTwo",
|
||||
path: image.path,
|
||||
caption: newArgs.length !== 0 ? newArgs.join(" ").replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%") : words.sort(() => 0.5 - Math.random()).slice(0, Math.floor(Math.random() * words.length + 1)).join(" "),
|
||||
type: image.type
|
||||
});
|
||||
if (processMessage.channel.messages.get(processMessage.id)) await processMessage.delete();
|
||||
return {
|
||||
file: buffer,
|
||||
name: `caption2.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["tags2", "meirl", "memecaption", "medotmecaption"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds a me.me caption/tag list to an image/GIF";
|
|
@ -1,24 +0,0 @@
|
|||
const fetch = require("node-fetch");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const data = await fetch("https://api.thecatapi.com/v1/images/search?format=json", {
|
||||
headers: {
|
||||
"x-api-key": process.env.CAT
|
||||
}
|
||||
});
|
||||
const json = await data.json();
|
||||
return {
|
||||
embed: {
|
||||
color: 16711680,
|
||||
image: {
|
||||
url: json[0].url
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["kitters", "kitties", "kitty", "cattos", "catto", "cats"];
|
||||
exports.category = 4;
|
||||
exports.help = "Gets a random cat picture";
|
||||
exports.requires = "cat";
|
|
@ -1,42 +0,0 @@
|
|||
const db = require("../utils/database.js");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (!message.channel.guild) return `${message.author.mention}, this command only works in servers!`;
|
||||
if (!message.member.permissions.has("administrator") && message.member.id !== process.env.OWNER) return `${message.author.mention}, you need to be an administrator to enable/disable me!`;
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide whether I should be enabled or disabled in this channel!`;
|
||||
if (args[0] !== "disable" && args[0] !== "enable") return `${message.author.mention}, that's not a valid option!`;
|
||||
|
||||
const guildDB = await db.getGuild(message.channel.guild.id);
|
||||
|
||||
if (args[0].toLowerCase() === "disable") {
|
||||
let channel;
|
||||
if (args[1] && args[1].match(/^<?[@#]?[&!]?\d+>?$/) && args[1] >= 21154535154122752) {
|
||||
const id = args[1].replaceAll("@", "").replaceAll("#", "").replaceAll("!", "").replaceAll("&", "").replaceAll("<", "").replaceAll(">", "");
|
||||
if (guildDB.disabled.includes(id)) return `${message.author.mention}, I'm already disabled in this channel!`;
|
||||
channel = message.channel.guild.channels.get(id);
|
||||
} else {
|
||||
if (guildDB.disabled.includes(message.channel.id)) return `${message.author.mention}, I'm already disabled in this channel!`;
|
||||
channel = message.channel;
|
||||
}
|
||||
|
||||
await db.disableChannel(channel);
|
||||
return `${message.author.mention}, I have been disabled in this channel. To re-enable me, just run \`${guildDB.prefix}channel enable\`.`;
|
||||
} else if (args[0].toLowerCase() === "enable") {
|
||||
let channel;
|
||||
if (args[1] && args[1].match(/^<?[@#]?[&!]?\d+>?$/) && args[1] >= 21154535154122752) {
|
||||
const id = args[1].replaceAll("@", "").replaceAll("#", "").replaceAll("!", "").replaceAll("&", "").replaceAll("<", "").replaceAll(">", "");
|
||||
if (!guildDB.disabled.includes(id)) return `${message.author.mention}, I'm not disabled in that channel!`;
|
||||
channel = message.channel.guild.channels.get(id);
|
||||
} else {
|
||||
if (!guildDB.disabled.includes(message.channel.id)) return `${message.author.mention}, I'm not disabled in this channel!`;
|
||||
channel = message.channel;
|
||||
}
|
||||
|
||||
await db.enableChannel(channel);
|
||||
return `${message.author.mention}, I have been re-enabled in this channel.`;
|
||||
}
|
||||
};
|
||||
|
||||
exports.category = 1;
|
||||
exports.help = "Enables/disables me in a channel";
|
||||
exports.params = "[enable/disable] {id}";
|
|
@ -1,20 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add radial blur!`;
|
||||
const { buffer, type} = await magick.run({
|
||||
cmd: "circle",
|
||||
path: image.path,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `circle.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["cblur", "radial", "radialblur"];
|
||||
exports.category = 5;
|
||||
exports.help = "Applies a radial blur effect on an image";
|
|
@ -1,42 +0,0 @@
|
|||
const client = require("../utils/client.js");
|
||||
const paginator = require("../utils/pagination/pagination.js");
|
||||
const database = require("../utils/database.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
if (message.channel.guild && !message.channel.guild.members.get(client.user.id).permissions.has("addReactions") && !message.channel.permissionsOf(client.user.id).has("addReactions")) return `${message.author.mention}, I don't have the \`Add Reactions\` permission!`;
|
||||
if (message.channel.guild && !message.channel.guild.members.get(client.user.id).permissions.has("embedLinks") && !message.channel.permissionsOf(client.user.id).has("embedLinks")) return `${message.author.mention}, I don't have the \`Embed Links\` permission!`;
|
||||
const counts = await database.getCounts();
|
||||
const countArray = [];
|
||||
const sortedValues = counts.sort((a, b) => {
|
||||
return b[1] - a[1];
|
||||
});
|
||||
for (const [key, value] of sortedValues) {
|
||||
countArray.push(`**${key}**: ${value}`);
|
||||
}
|
||||
const embeds = [];
|
||||
const groups = countArray.map((item, index) => {
|
||||
return index % 15 === 0 ? countArray.slice(index, index + 15) : null;
|
||||
}).filter((item) => {
|
||||
return item;
|
||||
});
|
||||
for (const [i, value] of groups.entries()) {
|
||||
embeds.push({
|
||||
"embed": {
|
||||
"title": "Command Usage Counts",
|
||||
"color": 16711680,
|
||||
"footer": {
|
||||
"text": `Page ${i + 1} of ${groups.length}`
|
||||
},
|
||||
"description": value.join("\n"),
|
||||
"author": {
|
||||
"name": message.author.username,
|
||||
"icon_url": message.author.avatarURL
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return paginator(message, embeds);
|
||||
};
|
||||
|
||||
exports.category = 1;
|
||||
exports.help = "Gets how many times every command was used";
|
|
@ -1,20 +0,0 @@
|
|||
const cowsay = require("cowsay2");
|
||||
const cows = require("cowsay2/cows");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (args.length === 0) {
|
||||
return `${message.author.mention}, you need to provide some text for the cow to say!`;
|
||||
} else if (cows[args[0].toLowerCase()] != undefined) {
|
||||
const cow = cows[args.shift().toLowerCase()];
|
||||
return `\`\`\`\n${cowsay.say(args.join(" "), {
|
||||
cow
|
||||
})}\n\`\`\``;
|
||||
} else {
|
||||
return `\`\`\`\n${cowsay.say(args.join(" "))}\n\`\`\``;
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["cow"];
|
||||
exports.category = 4;
|
||||
exports.help = "Makes an ASCII cow say a message";
|
||||
exports.params = "[text]";
|
|
@ -1,19 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to crop!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "crop",
|
||||
path: image.path,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `crop.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.category = 5;
|
||||
exports.help = "Crops an image to 1:1";
|
|
@ -1,7 +0,0 @@
|
|||
exports.run = async (message) => {
|
||||
return `${message.author.mention}, my DBL page can be found here: <https://top.gg/bot/429305856241172480>`;
|
||||
};
|
||||
|
||||
exports.aliases = ["discordbotlist", "botlist", "discordbots"];
|
||||
exports.category = 1;
|
||||
exports.help = "Gets my top.gg page";
|
|
@ -1,12 +0,0 @@
|
|||
const { clean } = require("../utils/misc.js");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide a string to decode!`;
|
||||
const b64Decoded = Buffer.from(args.join(" "), "base64").toString("utf-8");
|
||||
return `\`\`\`\n${await clean(b64Decoded)}\`\`\``;
|
||||
};
|
||||
|
||||
exports.aliases = ["b64decode", "base64decode"];
|
||||
exports.category = 1;
|
||||
exports.help = "Decodes a Base64 string";
|
||||
exports.params = "[text]";
|
|
@ -1,23 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a DeviantArt watermark!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "watermark",
|
||||
path: image.path,
|
||||
water: "./assets/images/deviantart.png",
|
||||
gravity: 5,
|
||||
resize: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `deviantart.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["da", "deviant"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds a DeviantArt watermark to an image";
|
|
@ -1,12 +0,0 @@
|
|||
exports.run = async (message, args) => {
|
||||
if (args.length === 0 || !args[0].match(/^\d+$/)) {
|
||||
return `🎲 The dice landed on ${Math.floor(Math.random() * 6) + 1}.`;
|
||||
} else {
|
||||
return `🎲 The dice landed on ${Math.floor(Math.random() * parseInt(args[0])) + 1}.`;
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["roll", "die", "rng", "random"];
|
||||
exports.category = 4;
|
||||
exports.help = "Rolls the dice";
|
||||
exports.params = "{number}";
|
|
@ -1,19 +0,0 @@
|
|||
const fetch = require("node-fetch");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const imageData = await fetch("https://dog.ceo/api/breeds/image/random");
|
||||
const json = await imageData.json();
|
||||
return {
|
||||
embed: {
|
||||
color: 16711680,
|
||||
image: {
|
||||
url: json.message
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["doggos", "doggo", "pupper", "puppers", "dogs", "puppy", "puppies", "pups", "pup"];
|
||||
exports.category = 4;
|
||||
exports.help = "Gets a random dog picture";
|
|
@ -1,20 +0,0 @@
|
|||
const client = require("../utils/client.js");
|
||||
|
||||
exports.run = async () => {
|
||||
let prefix = "";
|
||||
if (client.guilds.has("592399417676529688")) {
|
||||
const patrons = client.guilds.get("592399417676529688").members.filter((i) => {
|
||||
return i.roles.includes("741386733047906475");
|
||||
});
|
||||
prefix = "Thanks to the following patrons for their support:\n";
|
||||
for (const patron of patrons) {
|
||||
prefix += `**- ${patron.username}**\n`;
|
||||
}
|
||||
prefix += "\n";
|
||||
}
|
||||
return `${prefix}Like esmBot? Consider supporting the developer on Patreon to help keep it running! https://patreon.com/TheEssem`;
|
||||
};
|
||||
|
||||
exports.aliases = ["support", "patreon", "patrons"];
|
||||
exports.category = 1;
|
||||
exports.help = "Learn more about how you can support esmBot's development";
|
|
@ -1,21 +0,0 @@
|
|||
const emojiRegex = require("emoji-regex");
|
||||
|
||||
exports.run = async (message, args, content) => {
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide an emoji!`;
|
||||
if (content.split(" ")[0].match(/^<a?:.+:\d+>$/)) {
|
||||
return `https://cdn.discordapp.com/emojis/${content.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$2")}.${content.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$1") === "a" ? "gif" : "png"}`;
|
||||
} else if (args[0].match(emojiRegex)) {
|
||||
const codePoints = [];
|
||||
for (const codePoint of args[0]) {
|
||||
codePoints.push(codePoint.codePointAt(0).toString(16));
|
||||
}
|
||||
return `https://twemoji.maxcdn.com/v/latest/72x72/${codePoints.join("-").replace("-fe0f", "")}.png`;
|
||||
} else {
|
||||
return `${message.author.mention}, you need to provide a valid emoji to get an image!`;
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["e", "em", "hugemoji", "hugeemoji", "emoji"];
|
||||
exports.category = 1;
|
||||
exports.help = "Gets a raw emote image";
|
||||
exports.params = "[emote]";
|
|
@ -1,10 +0,0 @@
|
|||
exports.run = async (message, args) => {
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide a string to encode!`;
|
||||
const b64Encoded = Buffer.from(args.join(" ")).toString("base64");
|
||||
return `\`\`\`\n${b64Encoded}\`\`\``;
|
||||
};
|
||||
|
||||
exports.aliases = ["b64encode", "base64encode"];
|
||||
exports.category = 1;
|
||||
exports.help = "Encodes a Base64 string";
|
||||
exports.params = "[text]";
|
|
@ -1,27 +0,0 @@
|
|||
const { clean } = require("../utils/misc.js");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (message.author.id !== process.env.OWNER) return `${message.author.mention}, only the bot owner can use eval!`;
|
||||
const code = args.join(" ");
|
||||
try {
|
||||
const evaled = eval(code);
|
||||
const cleaned = await clean(evaled);
|
||||
const sendString = `\`\`\`js\n${cleaned}\n\`\`\``;
|
||||
if (sendString.length >= 2000) {
|
||||
return {
|
||||
text: "The result was too large, so here it is as a file:",
|
||||
file: cleaned,
|
||||
name: "result.txt"
|
||||
};
|
||||
} else {
|
||||
return sendString;
|
||||
}
|
||||
} catch (err) {
|
||||
return `\`ERROR\` \`\`\`xl\n${await clean(err)}\n\`\`\``;
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["run"];
|
||||
exports.category = 8;
|
||||
exports.help = "Executes JavaScript code";
|
||||
exports.params = "[code]";
|
|
@ -1,30 +0,0 @@
|
|||
const { clean } = require("../utils/misc.js");
|
||||
const util = require("util");
|
||||
const exec = util.promisify(require("child_process").exec);
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (message.author.id !== process.env.OWNER) return `${message.author.mention}, only the bot owner can use exec!`;
|
||||
const code = args.join(" ");
|
||||
try {
|
||||
const execed = await exec(code);
|
||||
if (execed.stderr) return `\`ERROR\` \`\`\`xl\n${await clean(execed.stderr)}\n\`\`\``;
|
||||
const cleaned = await clean(execed.stdout);
|
||||
const sendString = `\`\`\`bash\n${cleaned}\n\`\`\``;
|
||||
if (sendString.length >= 2000) {
|
||||
return {
|
||||
text: "The result was too large, so here it is as a file:",
|
||||
file: cleaned,
|
||||
name: "result.txt"
|
||||
};
|
||||
} else {
|
||||
return sendString;
|
||||
}
|
||||
} catch (err) {
|
||||
return `\`ERROR\` \`\`\`xl\n${await clean(err)}\n\`\`\``;
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["runcmd"];
|
||||
exports.category = 8;
|
||||
exports.help = "Executes a terminal command";
|
||||
exports.params = "[command]";
|
|
@ -1,21 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to explode!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "explode",
|
||||
path: image.path,
|
||||
amount: -1,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `explode.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["exp"];
|
||||
exports.category = 5;
|
||||
exports.help = "Explodes an image";
|
|
@ -1,9 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/explosion.ogg", message);
|
||||
};
|
||||
|
||||
exports.category = 6;
|
||||
exports.help = "Plays an explosion sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,10 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/ping.ogg", message);
|
||||
};
|
||||
|
||||
exports.aliases = ["notification", "notif"];
|
||||
exports.category = 6;
|
||||
exports.help = "Plays a Discord ping sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,10 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/fart.ogg", message);
|
||||
};
|
||||
|
||||
exports.aliases = ["toot"];
|
||||
exports.category = 6;
|
||||
exports.help = "Plays a fart sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,10 +0,0 @@
|
|||
const soundPlayer = require("../utils/soundplayer.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
return await soundPlayer.play("./assets/audio/fbi.ogg", message);
|
||||
};
|
||||
|
||||
exports.aliases = ["openup"];
|
||||
exports.category = 6;
|
||||
exports.help = "Plays the \"FBI OPEN UP\" sound effect";
|
||||
exports.requires = "sound";
|
|
@ -1,40 +0,0 @@
|
|||
const client = require("../utils/client.js");
|
||||
const regex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])/ig;
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (args.length !== 0) {
|
||||
if (regex.test(args.join(" "))) return `${message.author.mention}, you can't send a message containing a URL. If you want to report an issue, please join the esmBot Support server instead.`;
|
||||
const feedbackChannel = client.guilds.get("592399417676529688").channels.get("592429860769497098");
|
||||
feedbackChannel.createMessage({
|
||||
embed: {
|
||||
color: 16711680,
|
||||
timestamp: new Date(),
|
||||
thumbnail: {
|
||||
url: message.author.avatarURL
|
||||
},
|
||||
author: {
|
||||
name: "esmBot Feedback",
|
||||
icon_url: client.user.avatarURL
|
||||
},
|
||||
fields: [{
|
||||
name: "👥 Author:",
|
||||
value: `${message.author.username}#${message.author.discriminator}`
|
||||
}, {
|
||||
name: "👪 Server:",
|
||||
value: message.channel.guild ? message.channel.guild.name : "N/A"
|
||||
}, {
|
||||
name: "💬 Message:",
|
||||
value: args.join(" ")
|
||||
}]
|
||||
}
|
||||
});
|
||||
return `${message.author.mention}, your feedback has been sent!`;
|
||||
} else {
|
||||
return `${message.author.mention}, you need to provide some feedback to send!`;
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["request", "report", "complain", "compliment"];
|
||||
exports.category = 1;
|
||||
exports.help = "Leaves some feedback for the bot owner";
|
||||
exports.params = "[message]";
|
|
@ -1,36 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
const fs = require("fs");
|
||||
const emojiRegex = require("emoji-regex");
|
||||
const emoji = require("node-emoji");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to overlay a flag onto!`;
|
||||
if (args.length === 0 || !args[0].match(emojiRegex)) return `${message.author.mention}, you need to provide an emoji of a flag to overlay!`;
|
||||
const flag = emoji.unemojify(args[0]).replaceAll(":", "").replace("flag-", "");
|
||||
let path = `./assets/images/region-flags/png/${flag.toUpperCase()}.png`;
|
||||
if (flag === "🏴☠️") path = "./assets/images/pirateflag.png";
|
||||
if (flag === "rainbow-flag") path = "./assets/images/rainbowflag.png";
|
||||
if (flag === "checkered_flag") path = "./assets/images/checkeredflag.png";
|
||||
if (flag === "🏳️⚧️") path = "./assets/images/transflag.png";
|
||||
try {
|
||||
await fs.promises.access(path);
|
||||
} catch (e) {
|
||||
return `${message.author.mention}, that isn't a flag!`;
|
||||
}
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "flag",
|
||||
path: image.path,
|
||||
overlay: path,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `flag.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.params = "[flag]";
|
||||
exports.category = 5;
|
||||
exports.help = "Overlays a flag onto an image";
|
|
@ -1,19 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to flip!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "flip",
|
||||
path: image.path,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `flip.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.category = 5;
|
||||
exports.help = "Flips an image";
|
|
@ -1,21 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to flop!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "flip",
|
||||
path: image.path,
|
||||
flop: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `flop.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["flip2"];
|
||||
exports.category = 5;
|
||||
exports.help = "Flops an image";
|
|
@ -1,23 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide a GIF to freeze!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "freeze",
|
||||
path: image.path,
|
||||
loop: false,
|
||||
onlyGIF: true,
|
||||
type: image.type
|
||||
});
|
||||
if (type === "nogif") return `${message.author.mention}, that isn't a GIF!`;
|
||||
return {
|
||||
file: buffer,
|
||||
name: `freeze.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["noloop", "once"];
|
||||
exports.category = 5;
|
||||
exports.help = "Makes a GIF only play once";
|
|
@ -1,9 +0,0 @@
|
|||
exports.run = async (message, args) => {
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide some text to convert to fullwidth!`;
|
||||
return args.join("").replaceAll(/[A-Za-z0-9]/g, (s) => { return String.fromCharCode(s.charCodeAt(0) + 0xFEE0); });
|
||||
};
|
||||
|
||||
exports.aliases = ["aesthetic", "aesthetics", "aes"];
|
||||
exports.category = 4;
|
||||
exports.help = "Converts a message to fullwidth/aesthetic text";
|
||||
exports.params = "[text]";
|
37
commands/fun/8ball.js
Normal file
37
commands/fun/8ball.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
const { random } = require("../../utils/misc.js");
|
||||
|
||||
class EightBallCommand extends Command {
|
||||
static responses = [
|
||||
"It is certain",
|
||||
"It is decidedly so",
|
||||
"Without a doubt",
|
||||
"Yes, definitely",
|
||||
"You may rely on it",
|
||||
"As I see it, yes",
|
||||
"Most likely",
|
||||
"Outlook good",
|
||||
"Yes",
|
||||
"Signs point to yes",
|
||||
"Reply hazy, try again",
|
||||
"Ask again later",
|
||||
"Better not tell you now",
|
||||
"Cannot predict now",
|
||||
"Concentrate and ask again",
|
||||
"Don't count on it",
|
||||
"My reply is no",
|
||||
"My sources say no",
|
||||
"Outlook not so good",
|
||||
"Very doubtful"
|
||||
];
|
||||
|
||||
async run() {
|
||||
return `🎱 ${random(EightBallCommand.responses)}`;
|
||||
}
|
||||
|
||||
static description = "Asks the magic 8-ball a question";
|
||||
static aliases = ["magicball", "magikball", "magic8ball", "magik8ball", "eightball"];
|
||||
static arguments = ["{text}"];
|
||||
}
|
||||
|
||||
module.exports = EightBallCommand;
|
23
commands/fun/bird.js
Normal file
23
commands/fun/bird.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class BirdCommand extends Command {
|
||||
async run() {
|
||||
this.message.channel.sendTyping();
|
||||
const imageData = await fetch("http://shibe.online/api/birds");
|
||||
const json = await imageData.json();
|
||||
return {
|
||||
embed: {
|
||||
color: 16711680,
|
||||
image: {
|
||||
url: json[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets a random bird picture";
|
||||
static aliases = ["birb", "birds", "birbs"];
|
||||
}
|
||||
|
||||
module.exports = BirdCommand;
|
28
commands/fun/cat.js
Normal file
28
commands/fun/cat.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class CatCommand extends Command {
|
||||
async run() {
|
||||
this.message.channel.sendTyping();
|
||||
const data = await fetch("https://api.thecatapi.com/v1/images/search?format=json", {
|
||||
headers: {
|
||||
"x-api-key": process.env.CAT
|
||||
}
|
||||
});
|
||||
const json = await data.json();
|
||||
return {
|
||||
embed: {
|
||||
color: 16711680,
|
||||
image: {
|
||||
url: json[0].url
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets a random cat picture";
|
||||
static aliases = ["kitters", "kitties", "kitty", "cattos", "catto", "cats", "cta"];
|
||||
static requires = ["cat"];
|
||||
}
|
||||
|
||||
module.exports = CatCommand;
|
22
commands/fun/cowsay.js
Normal file
22
commands/fun/cowsay.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const cowsay = require("cowsay2");
|
||||
const cows = require("cowsay2/cows");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class CowsayCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) {
|
||||
return `${this.message.author.mention}, you need to provide some text for the cow to say!`;
|
||||
} else if (cows[this.args[0].toLowerCase()] != undefined) {
|
||||
const cow = cows[this.args.shift().toLowerCase()];
|
||||
return `\`\`\`\n${cowsay.say(this.args.join(" "), { cow })}\n\`\`\``;
|
||||
} else {
|
||||
return `\`\`\`\n${cowsay.say(this.args.join(" "))}\n\`\`\``;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Makes an ASCII cow say a message";
|
||||
static aliases = ["cow"];
|
||||
static arguments = ["{cow}", "[text]"];
|
||||
}
|
||||
|
||||
module.exports = CowsayCommand;
|
17
commands/fun/dice.js
Normal file
17
commands/fun/dice.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class DiceCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0 || !this.args[0].match(/^\d+$/)) {
|
||||
return `🎲 The dice landed on ${Math.floor(Math.random() * 6) + 1}.`;
|
||||
} else {
|
||||
return `🎲 The dice landed on ${Math.floor(Math.random() * parseInt(this.args[0])) + 1}.`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Rolls the dice";
|
||||
static aliases = ["roll", "die", "rng", "random"];
|
||||
static arguments = ["{number}"];
|
||||
}
|
||||
|
||||
module.exports = DiceCommand;
|
24
commands/fun/dog.js
Normal file
24
commands/fun/dog.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class DogCommand extends Command {
|
||||
async run() {
|
||||
this.message.channel.sendTyping();
|
||||
const imageData = await fetch("https://dog.ceo/api/breeds/image/random");
|
||||
const json = await imageData.json();
|
||||
return {
|
||||
embed: {
|
||||
color: 16711680,
|
||||
image: {
|
||||
url: json.message
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets a random dog picture";
|
||||
static aliases = ["doggos", "doggo", "pupper", "puppers", "dogs", "puppy", "puppies", "pups", "pup"];
|
||||
static arguments = ["{number}"];
|
||||
}
|
||||
|
||||
module.exports = DogCommand;
|
14
commands/fun/fullwidth.js
Normal file
14
commands/fun/fullwidth.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class FullwidthCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide some text to convert to fullwidth!`;
|
||||
return this.args.join("").replaceAll(/[A-Za-z0-9]/g, (s) => { return String.fromCharCode(s.charCodeAt(0) + 0xFEE0); });
|
||||
}
|
||||
|
||||
static description = "Converts a message to fullwidth/aesthetic text";
|
||||
static aliases = ["aesthetic", "aesthetics", "aes"];
|
||||
static arguments = ["[text]"];
|
||||
}
|
||||
|
||||
module.exports = FullwidthCommand;
|
20
commands/fun/homebrew.js
Normal file
20
commands/fun/homebrew.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const ImageCommand = require("../../classes/imageCommand.js");
|
||||
|
||||
class HomebrewCommand extends ImageCommand {
|
||||
params(args) {
|
||||
return {
|
||||
caption: args.join(" ").toLowerCase().replaceAll("\n", " ")
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Creates a Homebrew Channel edit";
|
||||
static aliases = ["hbc", "brew", "wiibrew"];
|
||||
static arguments = ["[text]"];
|
||||
|
||||
static requiresImage = false;
|
||||
static requiresText = true;
|
||||
static noText = "you need to provide some text to make a Homebrew Channel edit!";
|
||||
static command = "homebrew";
|
||||
}
|
||||
|
||||
module.exports = HomebrewCommand;
|
20
commands/fun/mc.js
Normal file
20
commands/fun/mc.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class MCCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide some text to generate a Minecraft achievement!`;
|
||||
this.message.channel.sendTyping();
|
||||
const request = await fetch(`https://www.minecraftskinstealer.com/achievement/a.php?i=13&h=Achievement+get%21&t=${encodeURIComponent(this.args.join("+"))}`);
|
||||
return {
|
||||
file: await request.buffer(),
|
||||
name: "mc.png"
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Generates a Minecraft achievement image";
|
||||
static aliases = ["ach", "achievement", "minecraft"];
|
||||
static arguments = ["[text]"];
|
||||
}
|
||||
|
||||
module.exports = MCCommand;
|
39
commands/fun/retro.js
Normal file
39
commands/fun/retro.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const magick = require("../../utils/image.js");
|
||||
const wrap = require("../../utils/wrap.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class RetroCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide some text to generate some retro text!`;
|
||||
this.message.channel.sendTyping();
|
||||
let [line1, line2, line3] = this.args.join(" ").replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%").split(",").map(elem => elem.trim());
|
||||
if (!line2 && line1.length > 15) {
|
||||
const [split1, split2, split3] = wrap(line1, { width: 15, indent: "" }).split("\n");
|
||||
line1 = split1;
|
||||
line2 = split2 ? split2 : "";
|
||||
line3 = split3 ? split3 : "";
|
||||
} else {
|
||||
if (!line2) {
|
||||
line2 = "";
|
||||
}
|
||||
if (!line3) {
|
||||
line3 = "";
|
||||
}
|
||||
}
|
||||
const { buffer } = await magick.run({
|
||||
cmd: "retro",
|
||||
line1,
|
||||
line2,
|
||||
line3
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: "retro.png"
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Generates a retro text image (separate lines with a comma)";
|
||||
static arguments = ["[text]", "{middle text}", "{bottom text}"];
|
||||
}
|
||||
|
||||
module.exports = RetroCommand;
|
34
commands/fun/rps.js
Normal file
34
commands/fun/rps.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
const misc = require("../../utils/misc.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class RPSCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0 || (this.args[0] !== "rock" && this.args[0] !== "paper" && this.args[0] !== "scissors")) return `${this.message.author.mention}, you need to choose whether you want to be rock, paper, or scissors!`;
|
||||
let emoji;
|
||||
let winOrLose;
|
||||
const result = misc.random(["rock", "paper", "scissors"]);
|
||||
switch (result) {
|
||||
case "rock":
|
||||
emoji = "✊";
|
||||
if (this.args[0].toLowerCase() === "paper") winOrLose = 1;
|
||||
break;
|
||||
case "paper":
|
||||
emoji = "✋";
|
||||
if (this.args[0].toLowerCase() === "scissors") winOrLose = 1;
|
||||
break;
|
||||
case "scissors":
|
||||
emoji = "✌";
|
||||
if (this.args[0].toLowerCase() === "rock") winOrLose = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this.args[0].toLowerCase() === result ? `${emoji} I chose ${result}. It's a tie!` : `${emoji} I chose ${result}. ${winOrLose ? "You win!" : "You lose!"}`;
|
||||
}
|
||||
|
||||
static description = "Plays rock, paper, scissors with me";
|
||||
static aliases = ["rockpaperscissors"];
|
||||
static arguments = ["[rock/paper/scissors]"];
|
||||
}
|
||||
|
||||
module.exports = RPSCommand;
|
21
commands/fun/sonic.js
Normal file
21
commands/fun/sonic.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
const wrap = require("../../utils/wrap.js");
|
||||
const ImageCommand = require("../../classes/imageCommand.js");
|
||||
|
||||
class SonicCommand extends ImageCommand {
|
||||
params(args) {
|
||||
const cleanedMessage = args.join(" ").replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%");
|
||||
return {
|
||||
text: wrap(cleanedMessage, {width: 15, indent: ""})
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Creates a Sonic speech bubble image";
|
||||
static arguments = ["[text]"];
|
||||
|
||||
static requiresImage = false;
|
||||
static requiresText = true;
|
||||
static noText = "you need to provide some text to make a Sonic meme!";
|
||||
static command = "sonic";
|
||||
}
|
||||
|
||||
module.exports = SonicCommand;
|
28
commands/fun/wikihow.js
Normal file
28
commands/fun/wikihow.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class WikihowCommand extends Command {
|
||||
async run() {
|
||||
this.message.channel.sendTyping();
|
||||
const request = await fetch("https://hargrimm-wikihow-v1.p.rapidapi.com/images?count=1", {
|
||||
headers: {
|
||||
"X-RapidAPI-Key": process.env.MASHAPE,
|
||||
"X-RapidAPI-Host": "hargrimm-wikihow-v1.p.rapidapi.com",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
});
|
||||
const json = await request.json();
|
||||
const image = await fetch(json["1"]);
|
||||
const imageBuffer = await image.buffer();
|
||||
return {
|
||||
file: imageBuffer,
|
||||
name: json["1"].split("/")[json["1"].split("/").length - 1]
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets a random WikiHow image";
|
||||
static aliases = ["wiki"];
|
||||
static requires = ["mashape"];
|
||||
}
|
||||
|
||||
module.exports = WikihowCommand;
|
31
commands/fun/xkcd.js
Normal file
31
commands/fun/xkcd.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class XKCDCommand extends Command {
|
||||
async run() {
|
||||
const url = this.args.length > 0 && this.args[0].match(/^\d+$/) ? `http://xkcd.com/${this.args[0]}/info.0.json` : "http://xkcd.com/info.0.json";
|
||||
try {
|
||||
const request = await fetch(url);
|
||||
const json = await request.json();
|
||||
const embed = {
|
||||
"embed": {
|
||||
"title": json.safe_title,
|
||||
"url": `https://xkcd.com/${json.num}`,
|
||||
"color": 16711680,
|
||||
"description": json.alt,
|
||||
"image": {
|
||||
"url": json.img
|
||||
}
|
||||
}
|
||||
};
|
||||
return embed;
|
||||
} catch {
|
||||
return `${this.message.author.mention}, I couldn't get that XKCD!`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Gets an XKCD comic";
|
||||
static arguments = ["{id}"];
|
||||
}
|
||||
|
||||
module.exports = XKCDCommand;
|
|
@ -1,23 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add New Funky Mode!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "watermark",
|
||||
path: image.path,
|
||||
water: "./assets/images/funky.png",
|
||||
gravity: 3,
|
||||
resize: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `funky.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["funkymode", "newfunkymode", "funkykong"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds the New Funky Mode banner to an image";
|
|
@ -1,20 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to make a GameXplain thumbnail meme!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "gamexplain",
|
||||
path: image.path,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `gamexplain.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["gx"];
|
||||
exports.category = 5;
|
||||
exports.help = "Makes a GameXplain thumbnail from an image";
|
25
commands/general/avatar.js
Normal file
25
commands/general/avatar.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class AvatarCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.mentions[0] !== undefined) {
|
||||
return this.message.mentions[0].dynamicAvatarURL(null, 1024);
|
||||
} else if (this.client.users.get(this.args[0]) !== undefined) {
|
||||
return this.client.users.get(this.args[0]).dynamicAvatarURL(null, 1024);
|
||||
} else if (this.args.join(" ") !== "" && this.message.channel.guild) {
|
||||
const userRegex = new RegExp(this.args.join("|"), "i");
|
||||
const member = this.message.channel.guild.members.find(element => {
|
||||
return userRegex.test(element.nick) ? userRegex.test(element.nick) : userRegex.test(element.username);
|
||||
});
|
||||
return member ? member.user.dynamicAvatarURL(null, 1024) : this.message.author.dynamicAvatarURL(null, 1024);
|
||||
} else {
|
||||
return this.message.author.dynamicAvatarURL(null, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Gets a user's avatar";
|
||||
static aliases = ["pfp", "ava"];
|
||||
static arguments = ["{mention/id}"];
|
||||
}
|
||||
|
||||
module.exports = AvatarCommand;
|
46
commands/general/channel.js
Normal file
46
commands/general/channel.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
const db = require("../../utils/database.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ChannelCommand extends Command {
|
||||
async run() {
|
||||
if (!this.message.channel.guild) return `${this.message.author.mention}, this command only works in servers!`;
|
||||
if (!this.message.member.permissions.has("administrator") && this.message.member.id !== process.env.OWNER) return `${this.message.author.mention}, you need to be an administrator to enable/disable me!`;
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide whether I should be enabled or disabled in this channel!`;
|
||||
if (this.args[0] !== "disable" && this.args[0] !== "enable") return `${this.message.author.mention}, that's not a valid option!`;
|
||||
|
||||
const guildDB = await db.getGuild(this.message.channel.guild.id);
|
||||
|
||||
if (this.args[0].toLowerCase() === "disable") {
|
||||
let channel;
|
||||
if (this.args[1] && this.args[1].match(/^<?[@#]?[&!]?\d+>?$/) && this.args[1] >= 21154535154122752n) {
|
||||
const id = this.args[1].replaceAll("@", "").replaceAll("#", "").replaceAll("!", "").replaceAll("&", "").replaceAll("<", "").replaceAll(">", "");
|
||||
if (guildDB.disabled.includes(id)) return `${this.message.author.mention}, I'm already disabled in this channel!`;
|
||||
channel = this.message.channel.guild.channels.get(id);
|
||||
} else {
|
||||
if (guildDB.disabled.includes(this.message.channel.id)) return `${this.message.author.mention}, I'm already disabled in this channel!`;
|
||||
channel = this.message.channel;
|
||||
}
|
||||
|
||||
await db.disableChannel(channel);
|
||||
return `${this.message.author.mention}, I have been disabled in this channel. To re-enable me, just run \`${guildDB.prefix}channel enable\`.`;
|
||||
} else if (this.args[0].toLowerCase() === "enable") {
|
||||
let channel;
|
||||
if (this.args[1] && this.args[1].match(/^<?[@#]?[&!]?\d+>?$/) && this.args[1] >= 21154535154122752) {
|
||||
const id = this.args[1].replaceAll("@", "").replaceAll("#", "").replaceAll("!", "").replaceAll("&", "").replaceAll("<", "").replaceAll(">", "");
|
||||
if (!guildDB.disabled.includes(id)) return `${this.message.author.mention}, I'm not disabled in that channel!`;
|
||||
channel = this.message.channel.guild.channels.get(id);
|
||||
} else {
|
||||
if (!guildDB.disabled.includes(this.message.channel.id)) return `${this.message.author.mention}, I'm not disabled in this channel!`;
|
||||
channel = this.message.channel;
|
||||
}
|
||||
|
||||
await db.enableChannel(channel);
|
||||
return `${this.message.author.mention}, I have been re-enabled in this channel.`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Enables/disables me in a channel";
|
||||
static arguments = ["[enable/disable]", "{id}"];
|
||||
}
|
||||
|
||||
module.exports = ChannelCommand;
|
46
commands/general/count.js
Normal file
46
commands/general/count.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
const paginator = require("../../utils/pagination/pagination.js");
|
||||
const database = require("../../utils/database.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class CountCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.channel.guild && !this.message.channel.permissionsOf(this.client.user.id).has("addReactions")) return `${this.message.author.mention}, I don't have the \`Add Reactions\` permission!`;
|
||||
if (this.message.channel.guild && !this.message.channel.permissionsOf(this.client.user.id).has("embedLinks")) return `${this.message.author.mention}, I don't have the \`Embed Links\` permission!`;
|
||||
const counts = await database.getCounts();
|
||||
const countArray = [];
|
||||
const sortedValues = counts.sort((a, b) => {
|
||||
return b[1] - a[1];
|
||||
});
|
||||
for (const [key, value] of sortedValues) {
|
||||
countArray.push(`**${key}**: ${value}`);
|
||||
}
|
||||
const embeds = [];
|
||||
const groups = countArray.map((item, index) => {
|
||||
return index % 15 === 0 ? countArray.slice(index, index + 15) : null;
|
||||
}).filter((item) => {
|
||||
return item;
|
||||
});
|
||||
for (const [i, value] of groups.entries()) {
|
||||
embeds.push({
|
||||
"embed": {
|
||||
"title": "Command Usage Counts",
|
||||
"color": 16711680,
|
||||
"footer": {
|
||||
"text": `Page ${i + 1} of ${groups.length}`
|
||||
},
|
||||
"description": value.join("\n"),
|
||||
"author": {
|
||||
"name": this.message.author.username,
|
||||
"icon_url": this.message.author.avatarURL
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return paginator(this.client, this.message, embeds);
|
||||
}
|
||||
|
||||
static description = "Gets how many times every command was used";
|
||||
static arguments = ["{mention/id}"];
|
||||
}
|
||||
|
||||
module.exports = CountCommand;
|
16
commands/general/decode.js
Normal file
16
commands/general/decode.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const { clean } = require("../../utils/misc.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class DecodeCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide a string to decode!`;
|
||||
const b64Decoded = Buffer.from(this.args.join(" "), "base64").toString("utf-8");
|
||||
return `\`\`\`\n${await clean(b64Decoded)}\`\`\``;
|
||||
}
|
||||
|
||||
static description = "Decodes a Base64 string";
|
||||
static aliases = ["b64decode", "base64decode"];
|
||||
static arguments = ["[text]"];
|
||||
}
|
||||
|
||||
module.exports = DecodeCommand;
|
20
commands/general/donate.js
Normal file
20
commands/general/donate.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class DonateCommand extends Command {
|
||||
async run() {
|
||||
let prefix = "";
|
||||
const patrons = await fetch("https://projectlounge.pw/patrons").then(data => data.json());
|
||||
prefix = "Thanks to the following patrons for their support:\n";
|
||||
for (const patron of patrons) {
|
||||
prefix += `**- ${patron}**\n`;
|
||||
}
|
||||
prefix += "\n";
|
||||
return `${prefix}Like esmBot? Consider supporting the developer on Patreon to help keep it running! https://patreon.com/TheEssem`;
|
||||
}
|
||||
|
||||
static description = "Learn more about how you can support esmBot's development";
|
||||
static aliases = ["support", "patreon", "patrons"];
|
||||
}
|
||||
|
||||
module.exports = DonateCommand;
|
25
commands/general/emote.js
Normal file
25
commands/general/emote.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const emojiRegex = require("emoji-regex");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class EmoteCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide an emoji!`;
|
||||
if (this.content.split(" ")[0].match(/^<a?:.+:\d+>$/)) {
|
||||
return `https://cdn.discordapp.com/emojis/${this.content.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$2")}.${this.content.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$1") === "a" ? "gif" : "png"}`;
|
||||
} else if (this.args[0].match(emojiRegex)) {
|
||||
const codePoints = [];
|
||||
for (const codePoint of this.args[0]) {
|
||||
codePoints.push(codePoint.codePointAt(0).toString(16));
|
||||
}
|
||||
return `https://twemoji.maxcdn.com/v/latest/72x72/${codePoints.join("-").replace("-fe0f", "")}.png`;
|
||||
} else {
|
||||
return `${this.message.author.mention}, you need to provide a valid emoji to get an image!`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Gets a raw emote image";
|
||||
static aliases = ["e", "em", "hugemoji", "hugeemoji", "emoji"];
|
||||
static arguments = ["[emote]"];
|
||||
}
|
||||
|
||||
module.exports = EmoteCommand;
|
15
commands/general/encode.js
Normal file
15
commands/general/encode.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class EncodeCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide a string to encode!`;
|
||||
const b64Encoded = Buffer.from(this.args.join(" ")).toString("base64");
|
||||
return `\`\`\`\n${b64Encoded}\`\`\``;
|
||||
}
|
||||
|
||||
static description = "Encodes a Base64 string";
|
||||
static aliases = ["b64encode", "base64encode"];
|
||||
static arguments = ["[text]"];
|
||||
}
|
||||
|
||||
module.exports = EncodeCommand;
|
31
commands/general/eval.js
Normal file
31
commands/general/eval.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
const { clean } = require("../../utils/misc.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class EvalCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.author.id !== process.env.OWNER) return `${this.message.author.mention}, only the bot owner can use eval!`;
|
||||
const code = this.args.join(" ");
|
||||
try {
|
||||
const evaled = eval(code);
|
||||
const cleaned = await clean(evaled);
|
||||
const sendString = `\`\`\`js\n${cleaned}\n\`\`\``;
|
||||
if (sendString.length >= 2000) {
|
||||
return {
|
||||
text: "The result was too large, so here it is as a file:",
|
||||
file: cleaned,
|
||||
name: "result.txt"
|
||||
};
|
||||
} else {
|
||||
return sendString;
|
||||
}
|
||||
} catch (err) {
|
||||
return `\`ERROR\` \`\`\`xl\n${await clean(err)}\n\`\`\``;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Executes JavaScript code";
|
||||
static aliases = ["run"];
|
||||
static arguments = ["[code]"];
|
||||
}
|
||||
|
||||
module.exports = EvalCommand;
|
34
commands/general/exec.js
Normal file
34
commands/general/exec.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
const { clean } = require("../../utils/misc.js");
|
||||
const util = require("util");
|
||||
const exec = util.promisify(require("child_process").exec);
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ExecCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.author.id !== process.env.OWNER) return `${this.message.author.mention}, only the bot owner can use exec!`;
|
||||
const code = this.args.join(" ");
|
||||
try {
|
||||
const execed = await exec(code);
|
||||
if (execed.stderr) return `\`ERROR\` \`\`\`xl\n${await clean(execed.stderr)}\n\`\`\``;
|
||||
const cleaned = await clean(execed.stdout);
|
||||
const sendString = `\`\`\`bash\n${cleaned}\n\`\`\``;
|
||||
if (sendString.length >= 2000) {
|
||||
return {
|
||||
text: "The result was too large, so here it is as a file:",
|
||||
file: cleaned,
|
||||
name: "result.txt"
|
||||
};
|
||||
} else {
|
||||
return sendString;
|
||||
}
|
||||
} catch (err) {
|
||||
return `\`ERROR\` \`\`\`xl\n${await clean(err)}\n\`\`\``;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Executes a shell command";
|
||||
static aliases = ["runcmd"];
|
||||
static arguments = ["[command]"];
|
||||
}
|
||||
|
||||
module.exports = ExecCommand;
|
100
commands/general/help.js
Normal file
100
commands/general/help.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
const database = require("../../utils/database.js");
|
||||
const collections = require("../../utils/collections.js");
|
||||
const misc = require("../../utils/misc.js");
|
||||
const paginator = require("../../utils/pagination/pagination.js");
|
||||
const help = require("../../utils/help.js");
|
||||
const tips = ["You can change the bot's prefix using the prefix command.", "Image commands also work with images previously posted in that channel.", "You can use the tags commands to save things for later use.", "You can visit https://projectlounge.pw/esmBot/help.html for a web version of this command list.", "You can view a command's aliases by putting the command name after the help command (e.g. help image).", "Parameters wrapped in [] are required, while parameters wrapped in {} are optional.", "esmBot is hosted and paid for completely out-of-pocket by the main developer. If you want to support development, please consider donating! https://patreon.com/TheEssem"];
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class HelpCommand extends Command {
|
||||
async run() {
|
||||
const { prefix } = this.message.channel.guild ? await database.getGuild(this.message.channel.guild.id) : "N/A";
|
||||
const commands = collections.commands;
|
||||
const aliases = collections.aliases;
|
||||
if (this.args.length !== 0 && (commands.has(this.args[0].toLowerCase()) || aliases.has(this.args[0].toLowerCase()))) {
|
||||
const command = aliases.has(this.args[0].toLowerCase()) ? collections.aliases.get(this.args[0].toLowerCase()) : this.args[0].toLowerCase();
|
||||
const info = collections.info.get(command);
|
||||
const countDB = await database.getCounts();
|
||||
const counts = countDB.reduce((acc, val) => {
|
||||
const [key, value] = val;
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
const embed = {
|
||||
"embed": {
|
||||
"author": {
|
||||
"name": "esmBot Help",
|
||||
"icon_url": this.client.user.avatarURL
|
||||
},
|
||||
"title": `${this.message.channel.guild ? prefix : ""}${command}`,
|
||||
"url": "https://projectlounge.pw/esmBot/help.html",
|
||||
"description": command === "tags" ? "The main tags command. Check the help page for more info: https://projectlounge.pw/esmBot/help.html" : info.description,
|
||||
"color": 16711680,
|
||||
"fields": [{
|
||||
"name": "Aliases",
|
||||
"value": info.aliases ? info.aliases.join(", ") : "None"
|
||||
}, {
|
||||
"name": "Times Used",
|
||||
"value": counts[command],
|
||||
"inline": true
|
||||
}, {
|
||||
"name": "Parameters",
|
||||
"value": command === "tags" ? "[name]" : (info.params ? (typeof info.params === "object" ? info.params.join(" ") : info.params) : "None"),
|
||||
"inline": true
|
||||
}]
|
||||
}
|
||||
};
|
||||
return embed;
|
||||
} else {
|
||||
const pages = [];
|
||||
for (const category of Object.keys(help.categories)) {
|
||||
const splitPages = help.categories[category].map((item, index) => {
|
||||
return index % 15 === 0 ? help.categories[category].slice(index, index + 15) : null;
|
||||
}).filter((item) => {
|
||||
return item;
|
||||
});
|
||||
const categoryStringArray = category.split("-");
|
||||
for (const index of categoryStringArray.keys()) {
|
||||
categoryStringArray[index] = categoryStringArray[index].charAt(0).toUpperCase() + categoryStringArray[index].slice(1);
|
||||
}
|
||||
for (const page of splitPages) {
|
||||
pages.push({
|
||||
title: categoryStringArray.join(" "),
|
||||
page: page
|
||||
});
|
||||
}
|
||||
}
|
||||
const embeds = [];
|
||||
for (const [i, value] of pages.entries()) {
|
||||
embeds.push({
|
||||
"embed": {
|
||||
"author": {
|
||||
"name": "esmBot Help",
|
||||
"icon_url": this.client.user.avatarURL
|
||||
},
|
||||
"title": value.title,
|
||||
"description": value.page.join("\n"),
|
||||
"color": 16711680,
|
||||
"footer": {
|
||||
"text": `Page ${i + 1} of ${pages.length}`
|
||||
},
|
||||
"fields": [{
|
||||
"name": "Prefix",
|
||||
"value": this.message.channel.guild ? prefix : "N/A"
|
||||
}, {
|
||||
"name": "Tip",
|
||||
"value": misc.random(tips)
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
return paginator(this.client, this.message, embeds);
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Gets a list of commands";
|
||||
static aliases = ["commands"];
|
||||
static arguments = ["{command}"];
|
||||
}
|
||||
|
||||
module.exports = HelpCommand;
|
40
commands/general/image.js
Normal file
40
commands/general/image.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
const paginator = require("../../utils/pagination/pagination.js");
|
||||
const { image_search } = require("duckduckgo-images-api");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ImageSearchCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.channel.guild && !this.message.channel.permissionsOf(this.client.user.id).has("addReactions")) return `${this.message.author.mention}, I don't have the \`Add Reactions\` permission!`;
|
||||
if (this.message.channel.guild && !this.message.channel.permissionsOf(this.client.user.id).has("embedLinks")) return `${this.message.author.mention}, I don't have the \`Embed Links\` permission!`;
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide something to search for!`;
|
||||
const embeds = [];
|
||||
const images = await image_search({ query: this.args.join(" "), moderate: true });
|
||||
if (images.error && images.error.code === 403) return `${this.message.author.mention}, the daily search quota has been exceeded. Check back later.`;
|
||||
if (images.length === 0) return `${this.message.author.mention}, I couldn't find any results!`;
|
||||
for (const [i, value] of images.entries()) {
|
||||
embeds.push({
|
||||
"embed": {
|
||||
"title": "Search Results",
|
||||
"color": 16711680,
|
||||
"footer": {
|
||||
"text": `Page ${i + 1} of ${images.length}`
|
||||
},
|
||||
"image": {
|
||||
"url": value.image
|
||||
},
|
||||
"author": {
|
||||
"name": this.message.author.username,
|
||||
"icon_url": this.message.author.avatarURL
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return paginator(this.client, this.message, embeds);
|
||||
}
|
||||
|
||||
static description = "Searches for images on DuckDuckGo";
|
||||
static aliases = ["im", "photo", "img"];
|
||||
static arguments = ["[query]"];
|
||||
}
|
||||
|
||||
module.exports = ImageSearchCommand;
|
30
commands/general/imagereload.js
Normal file
30
commands/general/imagereload.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
const image = require("../../utils/image.js");
|
||||
const logger = require("../../utils/logger.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ImageReloadCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.author.id !== process.env.OWNER) return `${this.message.author.mention}, only the bot owner can reload the image servers!`;
|
||||
await image.disconnect();
|
||||
await image.repopulate();
|
||||
let amount = 0;
|
||||
for (const server of image.servers) {
|
||||
try {
|
||||
await image.connect(server);
|
||||
amount += 1;
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
if (amount > 0) {
|
||||
return `Successfully connected to ${amount} image servers.`;
|
||||
} else {
|
||||
return `${this.message.author.mention}, I couldn't connect to any image servers!`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Attempts to reconnect to all available image processing servers";
|
||||
static aliases = ["magickconnect", "magick"];
|
||||
}
|
||||
|
||||
module.exports = ImageReloadCommand;
|
31
commands/general/imagestats.js
Normal file
31
commands/general/imagestats.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
const image = require("../../utils/image.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ImageStatsCommand extends Command {
|
||||
async run() {
|
||||
const embed = {
|
||||
embed: {
|
||||
"author": {
|
||||
"name": "esmBot Image Statistics",
|
||||
"icon_url": this.client.user.avatarURL
|
||||
},
|
||||
"color": 16711680,
|
||||
"description": `The bot is currently connected to ${image.connections.length} image server(s).`,
|
||||
"fields": []
|
||||
}
|
||||
};
|
||||
const servers = await image.getStatus();
|
||||
for (let i = 0; i < servers.length; i++) {
|
||||
embed.embed.fields.push({
|
||||
name: `Server ${i + 1}`,
|
||||
value: `Running Jobs: ${servers[i].runningJobs}\nQueued: ${servers[i].queued}\nMax Jobs: ${servers[i].max}`
|
||||
});
|
||||
}
|
||||
return embed;
|
||||
}
|
||||
|
||||
static description = "Gets some statistics about the image servers";
|
||||
static aliases = ["imgstat", "imstats", "imgstats", "imstat"];
|
||||
}
|
||||
|
||||
module.exports = ImageStatsCommand;
|
46
commands/general/info.js
Normal file
46
commands/general/info.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
const { version } = require("../../package.json");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class InfoCommand extends Command {
|
||||
async run() {
|
||||
return {
|
||||
"embed": {
|
||||
"color": 16711680,
|
||||
"author": {
|
||||
"name": "esmBot Info/Credits",
|
||||
"icon_url": this.client.user.avatarURL
|
||||
},
|
||||
"fields": [{
|
||||
"name": "ℹ️ Version:",
|
||||
"value": `v${version}${process.env.NODE_ENV === "development" ? "-dev" : ""}`
|
||||
},
|
||||
{
|
||||
"name": "📝 Credits:",
|
||||
"value": "Bot by **[Essem](https://essem.space)** and **[various contributors](https://github.com/esmBot/esmBot/graphs/contributors)**\nIcon by **[MintBorrow](https://mintborrow.newgrounds.com)**"
|
||||
},
|
||||
{
|
||||
"name": "💬 Total Servers:",
|
||||
"value": this.client.guilds.size
|
||||
},
|
||||
{
|
||||
"name": "✅ Official Server:",
|
||||
"value": "[Click here!](https://projectlounge.pw/support)"
|
||||
},
|
||||
{
|
||||
"name": "💻 Source Code:",
|
||||
"value": "[Click here!](https://github.com/esmBot/esmBot)"
|
||||
},
|
||||
{
|
||||
"name": "🐦 Twitter:",
|
||||
"value": "[Click here!](https://twitter.com/esmBot_)"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets some info and credits about me";
|
||||
static aliases = ["botinfo", "credits"];
|
||||
}
|
||||
|
||||
module.exports = InfoCommand;
|
12
commands/general/invite.js
Normal file
12
commands/general/invite.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class InviteCommand extends Command {
|
||||
async run() {
|
||||
return `${this.message.author.mention}, you can invite me to your server here: <https://projectlounge.pw/invite>`;
|
||||
}
|
||||
|
||||
static description = "Gets my invite link";
|
||||
static aliases = ["botinfo", "credits"];
|
||||
}
|
||||
|
||||
module.exports = InviteCommand;
|
22
commands/general/lengthen.js
Normal file
22
commands/general/lengthen.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const urlCheck = require("../../utils/urlcheck.js");
|
||||
const fetch = require("node-fetch");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class LengthenCommand extends Command {
|
||||
async run() {
|
||||
this.message.channel.sendTyping();
|
||||
if (this.args.length === 0 || !urlCheck(this.args[0])) return `${this.message.author.mention}, you need to provide a short URL to lengthen!`;
|
||||
if (urlCheck(this.args[0])) {
|
||||
const url = await fetch(encodeURI(this.args[0]), { redirect: "manual" });
|
||||
return url.headers.get("location") || this.args[0];
|
||||
} else {
|
||||
return `${this.message.author.mention}, that isn't a URL!`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Lengthens a short URL";
|
||||
static aliases = ["longurl", "lengthenurl", "longuri", "lengthenuri", "unshorten"];
|
||||
static arguments = ["[url]"];
|
||||
}
|
||||
|
||||
module.exports = LengthenCommand;
|
13
commands/general/ping.js
Normal file
13
commands/general/ping.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class PingCommand extends Command {
|
||||
async run() {
|
||||
const pingMessage = await this.message.channel.createMessage("🏓 Ping?");
|
||||
return pingMessage.edit(`🏓 Pong!\n\`\`\`\nLatency: ${pingMessage.timestamp - this.message.timestamp}ms${this.message.channel.guild ? `\nShard Latency: ${Math.round(this.client.shards.get(this.client.guildShardMap[this.message.channel.guild.id]).latency)}ms` : ""}\n\`\`\``);
|
||||
}
|
||||
|
||||
static description = "Pings Discord's servers";
|
||||
static aliases = ["pong"];
|
||||
}
|
||||
|
||||
module.exports = PingCommand;
|
22
commands/general/prefix.js
Normal file
22
commands/general/prefix.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const database = require("../../utils/database.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class PrefixCommand extends Command {
|
||||
async run() {
|
||||
if (!this.message.channel.guild) return `${this.message.author.mention}, this command only works in servers!`;
|
||||
const guild = await database.getGuild(this.message.channel.guild.id);
|
||||
if (this.args.length !== 0) {
|
||||
if (!this.message.member.permissions.has("administrator") && this.message.member.id !== process.env.OWNER) return `${this.message.author.mention}, you need to be an administrator to change the bot prefix!`;
|
||||
await database.setPrefix(this.args[0], this.message.channel.guild);
|
||||
return `The prefix has been changed to ${this.args[0]}.`;
|
||||
} else {
|
||||
return `${this.message.author.mention}, the current prefix is \`${guild.prefix}\`.`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Checks/changes the server prefix";
|
||||
static aliases = ["setprefix", "changeprefix", "checkprefix"];
|
||||
static arguments = ["{prefix}"];
|
||||
}
|
||||
|
||||
module.exports = PrefixCommand;
|
37
commands/general/qrcreate.js
Normal file
37
commands/general/qrcreate.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
const qrcode = require("qrcode");
|
||||
const stream = require("stream");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class QrCreateCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide some text to generate a QR code!`;
|
||||
this.message.channel.sendTyping();
|
||||
const writable = new stream.PassThrough();
|
||||
qrcode.toFileStream(writable, this.content, { margin: 1 });
|
||||
const file = await this.streamToBuf(writable);
|
||||
return {
|
||||
file: file,
|
||||
name: "qr.png"
|
||||
};
|
||||
}
|
||||
|
||||
streamToBuf(stream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
stream.on("data", (chunk) => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
stream.once("error", (error) => {
|
||||
reject(error);
|
||||
});
|
||||
stream.once("end", () => {
|
||||
resolve(Buffer.concat(chunks));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static description = "Generates a QR code";
|
||||
static arguments = ["[text]"];
|
||||
}
|
||||
|
||||
module.exports = QrCreateCommand;
|
22
commands/general/qrread.js
Normal file
22
commands/general/qrread.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const jsqr = require("jsqr");
|
||||
const fetch = require("node-fetch");
|
||||
const sharp = require("sharp");
|
||||
const { clean } = require("../../utils/misc.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class QrReadCommand extends Command {
|
||||
async run() {
|
||||
const image = await require("../../utils/imagedetect.js")(this.client, this.message);
|
||||
if (image === undefined) return `${this.message.author.mention}, you need to provide an image with a QR code to read!`;
|
||||
this.message.channel.sendTyping();
|
||||
const data = await (await fetch(image.path)).buffer();
|
||||
const rawData = await sharp(data).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
||||
const qrBuffer = jsqr(rawData.data, rawData.info.width, rawData.info.height);
|
||||
if (!qrBuffer) return `${this.message.author.mention}, I couldn't find a QR code!`;
|
||||
return `\`\`\`\n${await clean(qrBuffer.data)}\n\`\`\``;
|
||||
}
|
||||
|
||||
static description = "Reads a QR code";
|
||||
}
|
||||
|
||||
module.exports = QrReadCommand;
|
20
commands/general/reload.js
Normal file
20
commands/general/reload.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const handler = require("../../utils/handler.js");
|
||||
const collections = require("../../utils/collections.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ReloadCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.author.id !== process.env.OWNER) return `${this.message.author.mention}, only the bot owner can reload commands!`;
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide a command to reload!`;
|
||||
const result = await handler.unload(this.args[0]);
|
||||
if (result) return result;
|
||||
const result2 = await handler.load(collections.paths.get(this.args[0]));
|
||||
if (result2) return result2;
|
||||
return `${this.message.author.mention}, the command \`${this.args[0]}\` has been reloaded.`;
|
||||
}
|
||||
|
||||
static description = "Reloads a command";
|
||||
static arguments = ["[command]"];
|
||||
}
|
||||
|
||||
module.exports = ReloadCommand;
|
19
commands/general/restart.js
Normal file
19
commands/general/restart.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
const handler = require("../../utils/handler.js");
|
||||
const collections = require("../../utils/collections.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class RestartCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.author.id !== process.env.OWNER) return `${this.message.author.mention}, only the bot owner can restart me!`;
|
||||
await this.message.channel.createMessage(`${this.message.author.mention}, esmBot is restarting.`);
|
||||
for (const command of collections.commands) {
|
||||
await handler.unload(command);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
static description = "Restarts me";
|
||||
static aliases = ["reboot"];
|
||||
}
|
||||
|
||||
module.exports = RestartCommand;
|
52
commands/general/serverinfo.js
Normal file
52
commands/general/serverinfo.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class ServerInfoCommand extends Command {
|
||||
async run() {
|
||||
if (!this.message.channel.guild) return `${this.message.author.mention}, this command only works in servers!`;
|
||||
const owner = await this.message.channel.guild.members.get(this.message.channel.guild.ownerID);
|
||||
return {
|
||||
"embed": {
|
||||
"title": this.message.channel.guild.name,
|
||||
"thumbnail": {
|
||||
"url": this.message.channel.guild.iconURL
|
||||
},
|
||||
"color": 16711680,
|
||||
"fields": [
|
||||
{
|
||||
"name": "🔢 **ID:**",
|
||||
"value": this.message.channel.guild.id
|
||||
},
|
||||
{
|
||||
"name": "👤 **Owner:**",
|
||||
"value": owner ? `${owner.user.username}#${owner.user.discriminator}` : this.message.channel.guild.ownerID
|
||||
},
|
||||
{
|
||||
"name": "🗺 **Region:**",
|
||||
"value": this.message.channel.guild.region
|
||||
},
|
||||
{
|
||||
"name": "🗓 **Created on:**",
|
||||
"value": new Date(this.message.channel.guild.createdAt).toString()
|
||||
},
|
||||
{
|
||||
"name": "👥 **Users:**",
|
||||
"value": this.message.channel.guild.memberCount
|
||||
},
|
||||
{
|
||||
"name": "💬 **Channels:**",
|
||||
"value": this.message.channel.guild.channels.size
|
||||
},
|
||||
{
|
||||
"name": "😃 **Emojis:**",
|
||||
"value": this.message.channel.guild.emojis.length
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets some info about the server";
|
||||
static aliases = ["server"];
|
||||
}
|
||||
|
||||
module.exports = ServerInfoCommand;
|
15
commands/general/snowflake.js
Normal file
15
commands/general/snowflake.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class SnowflakeCommand extends Command {
|
||||
async run() {
|
||||
if (!this.args[0]) return `${this.message.author.mention}, you need to provide a snowflake ID!`;
|
||||
if (!this.args[0].match(/^<?[@#]?[&!]?\d+>?$/) && this.args[0] < 21154535154122752) return `${this.message.author.mention}, that's not a valid snowflake!`;
|
||||
return new Date((this.args[0].replaceAll("@", "").replaceAll("#", "").replaceAll("!", "").replaceAll("&", "").replaceAll("<", "").replaceAll(">", "") / 4194304) + 1420070400000).toUTCString();
|
||||
}
|
||||
|
||||
static description = "Converts a Discord snowflake id into a timestamp";
|
||||
static aliases = ["timestamp", "snowstamp", "snow"];
|
||||
static arguments = ["[id]"];
|
||||
}
|
||||
|
||||
module.exports = SnowflakeCommand;
|
20
commands/general/soundreload.js
Normal file
20
commands/general/soundreload.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const soundPlayer = require("../../utils/soundplayer.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class SoundReloadCommand extends Command {
|
||||
async run() {
|
||||
if (this.message.author.id !== process.env.OWNER) return `${this.message.author.mention}, only the bot owner can reload Lavalink!`;
|
||||
const soundStatus = await soundPlayer.checkStatus();
|
||||
if (!soundStatus) {
|
||||
const length = await soundPlayer.connect(this.client);
|
||||
return `Successfully connected to ${length} Lavalink node(s).`;
|
||||
} else {
|
||||
return `${this.message.author.mention}, I couldn't connect to any Lavalink nodes!`;
|
||||
}
|
||||
}
|
||||
|
||||
static description = "Attempts to reconnect to all available Lavalink nodes";
|
||||
static aliases = ["lava", "lavalink", "lavaconnect", "soundconnect"];
|
||||
}
|
||||
|
||||
module.exports = SoundReloadCommand;
|
59
commands/general/stats.js
Normal file
59
commands/general/stats.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
const { version } = require("../../package.json");
|
||||
const day = require("dayjs");
|
||||
day.extend(require("dayjs/plugin/duration"));
|
||||
const os = require("os");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class StatsCommand extends Command {
|
||||
async run() {
|
||||
const duration = day.duration(this.client.uptime).format(" D [days], H [hrs], m [mins], s [secs]");
|
||||
const uptime = day.duration(process.uptime(), "seconds").format(" D [days], H [hrs], m [mins], s [secs]");
|
||||
return {
|
||||
embed: {
|
||||
"author": {
|
||||
"name": "esmBot Statistics",
|
||||
"icon_url": this.client.user.avatarURL
|
||||
},
|
||||
"color": 16711680,
|
||||
"fields": [{
|
||||
"name": "Version",
|
||||
"value": `v${version}${process.env.NODE_ENV === "development" ? "-dev" : ""}`
|
||||
},
|
||||
{
|
||||
"name": "Memory Usage",
|
||||
"value": `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`
|
||||
},
|
||||
{
|
||||
"name": "Shard",
|
||||
"value": this.client.guildShardMap[this.message.channel.guild.id]
|
||||
},
|
||||
{
|
||||
"name": "Uptime",
|
||||
"value": uptime
|
||||
},
|
||||
{
|
||||
"name": "Connection Uptime",
|
||||
"value": duration
|
||||
},
|
||||
{
|
||||
"name": "Host",
|
||||
"value": `${os.type()} ${os.release()} (${os.arch()})`
|
||||
},
|
||||
{
|
||||
"name": "Library",
|
||||
"value": `Eris ${require("eris").VERSION}`
|
||||
},
|
||||
{
|
||||
"name": "Node.js Version",
|
||||
"value": process.version
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets some statistics about me";
|
||||
static aliases = ["status", "stat"];
|
||||
}
|
||||
|
||||
module.exports = StatsCommand;
|
57
commands/general/userinfo.js
Normal file
57
commands/general/userinfo.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
const Command = require("../../classes/command.js");
|
||||
|
||||
class UserInfoCommand extends Command {
|
||||
async run() {
|
||||
const getUser = this.message.mentions.length >= 1 ? this.message.mentions[0] : (this.args.length !== 0 ? this.client.users.get(this.args[0]) : this.message.author);
|
||||
let user;
|
||||
if (getUser) {
|
||||
user = getUser;
|
||||
} else if (this.args.join(" ") !== "") {
|
||||
const userRegex = new RegExp(this.args.join("|"), "i");
|
||||
const member = this.client.users.find(element => {
|
||||
return userRegex.test(element.username);
|
||||
});
|
||||
user = member ? member : this.message.author;
|
||||
} else {
|
||||
user = this.message.author;
|
||||
}
|
||||
const member = this.message.channel.guild ? this.message.channel.guild.members.get(user.id) : undefined;
|
||||
return {
|
||||
"embed": {
|
||||
"title": `${user.username}#${user.discriminator}`,
|
||||
"thumbnail": {
|
||||
"url": user.avatarURL
|
||||
},
|
||||
"color": 16711680,
|
||||
"fields": [
|
||||
{
|
||||
"name": "🔢 **ID:**",
|
||||
"value": user.id
|
||||
},
|
||||
{
|
||||
"name": "📛 **Nickname:**",
|
||||
"value": member ? (member.nick ? member.nick : "None") : "N/A"
|
||||
},
|
||||
{
|
||||
"name": "🤖 **Bot:**",
|
||||
"value": user.bot ? "Yes" : "No"
|
||||
},
|
||||
{
|
||||
"name": "🗓️ **Joined Discord on:**",
|
||||
"value": new Date(user.createdAt).toString()
|
||||
},
|
||||
{
|
||||
"name": "💬 **Joined this server on:**",
|
||||
"value": member ? new Date(member.joinedAt).toString() : "N/A"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static description = "Gets info about a user";
|
||||
static aliases = ["user"];
|
||||
static arguments = ["[mention/id]"];
|
||||
}
|
||||
|
||||
module.exports = UserInfoCommand;
|
32
commands/general/youtube.js
Normal file
32
commands/general/youtube.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const fetch = require("node-fetch");
|
||||
const { decodeEntities } = require("../../utils/misc.js");
|
||||
const paginator = require("../../utils/pagination/pagination.js");
|
||||
const Command = require("../../classes/command.js");
|
||||
|
||||
class YouTubeCommand extends Command {
|
||||
async run() {
|
||||
if (this.args.length === 0) return `${this.message.author.mention}, you need to provide something to search for!`;
|
||||
this.message.channel.sendTyping();
|
||||
const messages = [];
|
||||
const request = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&q=${encodeURIComponent(this.args.join(" "))}&key=${process.env.GOOGLE}&maxResults=50`);
|
||||
const result = await request.json();
|
||||
if (result.error && result.error.code === 403) return `${this.message.author.mention}, I've exceeded my YouTube API search quota for the day. Check back later.`;
|
||||
for (const [i, value] of result.items.entries()) {
|
||||
if (value.id.kind === "youtube#channel") {
|
||||
messages.push(`Page ${i + 1} of ${result.items.length}\n<:youtube:637020823005167626> **${decodeEntities(value.snippet.title).replaceAll("*", "\\*")}**\nhttps://youtube.com/channel/${value.id.channelId}`);
|
||||
} else if (value.id.kind === "youtube#playlist") {
|
||||
messages.push(`Page ${i + 1} of ${result.items.length}\n<:youtube:637020823005167626> **${decodeEntities(value.snippet.title).replaceAll("*", "\\*")}**\nCreated by **${decodeEntities(value.snippet.channelTitle).replaceAll("*", "\\*")}**\nhttps://youtube.com/playlist?list=${value.id.playlistId}`);
|
||||
} else {
|
||||
messages.push(`Page ${i + 1} of ${result.items.length}\n<:youtube:637020823005167626> **${decodeEntities(value.snippet.title).replaceAll("*", "\\*")}**\nUploaded by **${decodeEntities(value.snippet.channelTitle).replaceAll("*", "\\*")}** on **${value.snippet.publishedAt.split("T")[0]}**\nhttps://youtube.com/watch?v=${value.id.videoId}`);
|
||||
}
|
||||
}
|
||||
return paginator(this.client, this.message, messages);
|
||||
}
|
||||
|
||||
static description = "Searches YouTube";
|
||||
static aliases = ["yt", "video", "ytsearch"];
|
||||
static arguments = ["[query]"];
|
||||
static requires = "google";
|
||||
}
|
||||
|
||||
module.exports = YouTubeCommand;
|
|
@ -1,21 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to spin!`;
|
||||
const processMessage = await message.channel.createMessage(`${process.env.PROCESSING_EMOJI || "<a:processing:479351417102925854>"} Processing... This might take a while`);
|
||||
const { buffer } = await magick.run({
|
||||
cmd: "globe",
|
||||
path: image.path,
|
||||
type: image.type
|
||||
});
|
||||
if (processMessage.channel.messages.get(processMessage.id)) await processMessage.delete();
|
||||
return {
|
||||
file: buffer,
|
||||
name: "globe.gif"
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["rotate", "sphere"];
|
||||
exports.category = 5;
|
||||
exports.help = "Spins an image";
|
|
@ -1,21 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to mirror!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "mirror",
|
||||
path: image.path,
|
||||
first: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `haah.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["magik4", "mirror2"];
|
||||
exports.category = 5;
|
||||
exports.help = "Mirrors the left side of an image onto the right";
|
124
commands/help.js
124
commands/help.js
|
@ -1,124 +0,0 @@
|
|||
const database = require("../utils/database.js");
|
||||
const collections = require("../utils/collections.js");
|
||||
const client = require("../utils/client.js");
|
||||
const misc = require("../utils/misc.js");
|
||||
const paginator = require("../utils/pagination/pagination.js");
|
||||
const tips = ["You can change the bot's prefix using the prefix command.", "Image commands also work with images previously posted in that channel.", "You can use the tags commands to save things for later use.", "You can visit https://projectlounge.pw/esmBot/help.html for a web version of this command list.", "You can view a command's aliases by putting the command name after the help command (e.g. help image).", "Parameters wrapped in [] are required, while parameters wrapped in {} are optional.", "esmBot is hosted and paid for completely out-of-pocket by the main developer. If you want to support development, please consider donating! https://patreon.com/TheEssem"];
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
const { prefix } = message.channel.guild ? await database.getGuild(message.channel.guild.id) : "N/A";
|
||||
const commands = collections.commands;
|
||||
const aliases = collections.aliases;
|
||||
if (args.length !== 0 && (commands.has(args[0].toLowerCase()) || aliases.has(args[0].toLowerCase()))) {
|
||||
const command = aliases.has(args[0].toLowerCase()) ? collections.aliases.get(args[0].toLowerCase()) : args[0].toLowerCase();
|
||||
const info = collections.info.get(command);
|
||||
const countDB = await database.getCounts();
|
||||
const counts = countDB.reduce((acc, val) => {
|
||||
const [key, value] = val;
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
const embed = {
|
||||
"embed": {
|
||||
"author": {
|
||||
"name": "esmBot Help",
|
||||
"icon_url": client.user.avatarURL
|
||||
},
|
||||
"title": `${message.channel.guild ? prefix : ""}${command}`,
|
||||
"url": "https://projectlounge.pw/esmBot/help.html",
|
||||
"description": command === "tags" ? "The main tags command. Check the help page for more info: https://projectlounge.pw/esmBot/help.html" : info.description,
|
||||
"color": 16711680,
|
||||
"fields": [{
|
||||
"name": "Aliases",
|
||||
"value": info.aliases ? info.aliases.join(", ") : "None"
|
||||
}, {
|
||||
"name": "Times Used",
|
||||
"value": counts[command],
|
||||
"inline": true
|
||||
}, {
|
||||
"name": "Parameters",
|
||||
"value": command === "tags" ? "[name]" : info.params ? info.params : "None",
|
||||
"inline": true
|
||||
}]
|
||||
}
|
||||
};
|
||||
return embed;
|
||||
} else {
|
||||
const categories = {
|
||||
general: [],
|
||||
moderation: [],
|
||||
tags: ["**Every command in this category is a subcommand of the tag command.**\n"],
|
||||
fun: [],
|
||||
images: ["**These commands support the PNG, JPEG, WEBP (static), and GIF (animated or static) formats.**\n"],
|
||||
soundboard: [],
|
||||
music: []
|
||||
};
|
||||
for (const [command] of commands) {
|
||||
const category = collections.info.get(command).category;
|
||||
const description = collections.info.get(command).description;
|
||||
const params = collections.info.get(command).params;
|
||||
if (category === 1) {
|
||||
categories.general.push(`**${command}**${params ? ` ${params}` : ""} - ${description}`);
|
||||
} else if (category === 2) {
|
||||
categories.moderation.push(`**${command}**${params ? ` ${params}` : ""} - ${description}`);
|
||||
} else if (category === 3) {
|
||||
const subCommands = [...Object.keys(description)];
|
||||
for (const subCommand of subCommands) {
|
||||
categories.tags.push(`**tags${subCommand !== "default" ? ` ${subCommand}` : ""}**${params[subCommand] ? ` ${params[subCommand]}` : ""} - ${description[subCommand]}`);
|
||||
}
|
||||
} else if (category === 4) {
|
||||
categories.fun.push(`**${command}**${params ? ` ${params}` : ""} - ${description}`);
|
||||
} else if (category === 5) {
|
||||
categories.images.push(`**${command}**${params ? ` ${params}` : ""} - ${description}`);
|
||||
} else if (category === 6) {
|
||||
categories.soundboard.push(`**${command}**${params ? ` ${params}` : ""} - ${description}`);
|
||||
} else if (category === 7) {
|
||||
categories.music.push(`**${command}**${params ? ` ${params}` : ""} - ${description}`);
|
||||
}
|
||||
}
|
||||
const pages = [];
|
||||
for (const category of Object.keys(categories)) {
|
||||
const splitPages = categories[category].map((item, index) => {
|
||||
return index % 15 === 0 ? categories[category].slice(index, index + 15) : null;
|
||||
}).filter((item) => {
|
||||
return item;
|
||||
});
|
||||
for (const page of splitPages) {
|
||||
pages.push({
|
||||
title: category.charAt(0).toUpperCase() + category.slice(1),
|
||||
page: page
|
||||
});
|
||||
}
|
||||
}
|
||||
const embeds = [];
|
||||
for (const [i, value] of pages.entries()) {
|
||||
embeds.push({
|
||||
"embed": {
|
||||
"author": {
|
||||
"name": "esmBot Help",
|
||||
"icon_url": client.user.avatarURL
|
||||
},
|
||||
"title": value.title,
|
||||
"description": value.page.join("\n"),
|
||||
"color": 16711680,
|
||||
"footer": {
|
||||
"text": `Page ${i + 1} of ${pages.length}`
|
||||
},
|
||||
"fields": [{
|
||||
"name": "Prefix",
|
||||
"value": message.channel.guild ? prefix : "N/A"
|
||||
}, {
|
||||
"name": "Tip",
|
||||
"value": misc.random(tips)
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
return paginator(message, embeds);
|
||||
}
|
||||
};
|
||||
|
||||
exports.aliases = ["commands"];
|
||||
exports.category = 1;
|
||||
exports.help = "Gets a list of commands";
|
||||
exports.params = "{command}";
|
|
@ -1,19 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message, args) => {
|
||||
if (args.length === 0) return `${message.author.mention}, you need to provide some text to make a Homebrew Channel edit!`;
|
||||
message.channel.sendTyping();
|
||||
const { buffer } = await magick.run({
|
||||
cmd: "homebrew",
|
||||
caption: args.join(" ").toLowerCase().replaceAll("\n", " ")
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: "homebrew.png"
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["hbc", "brew", "wiibrew"];
|
||||
exports.category = 4;
|
||||
exports.help = "Creates a Homebrew Channel edit";
|
||||
exports.params = "[text]";
|
|
@ -1,21 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to mirror!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "mirror",
|
||||
path: image.path,
|
||||
vertical: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `hooh.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["magik6", "mirror4"];
|
||||
exports.category = 5;
|
||||
exports.help = "Mirrors the bottom of an image onto the top";
|
|
@ -1,23 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a Hypercam watermark!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "watermark",
|
||||
path: image.path,
|
||||
water: "./assets/images/hypercam.png",
|
||||
gravity: 1,
|
||||
resize: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `hypercam.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.aliases = ["hcam"];
|
||||
exports.category = 5;
|
||||
exports.help = "Adds the Hypercam watermark to an image";
|
|
@ -1,23 +0,0 @@
|
|||
const magick = require("../utils/image.js");
|
||||
|
||||
exports.run = async (message) => {
|
||||
message.channel.sendTyping();
|
||||
const image = await require("../utils/imagedetect.js")(message);
|
||||
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a iFunny watermark!`;
|
||||
const { buffer, type } = await magick.run({
|
||||
cmd: "watermark",
|
||||
path: image.path,
|
||||
water: "./assets/images/ifunny.png",
|
||||
gravity: 8,
|
||||
resize: true,
|
||||
append: true,
|
||||
type: image.type
|
||||
});
|
||||
return {
|
||||
file: buffer,
|
||||
name: `ifunny.${type}`
|
||||
};
|
||||
};
|
||||
|
||||
exports.category = 5;
|
||||
exports.help = "Adds the iFunny watermark to an image";
|
16
commands/image-editing/9gag.js
Normal file
16
commands/image-editing/9gag.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const ImageCommand = require("../../classes/imageCommand.js");
|
||||
|
||||
class NineGagCommand extends ImageCommand {
|
||||
params = {
|
||||
water: "./assets/images/9gag.png",
|
||||
gravity: 6
|
||||
};
|
||||
|
||||
static description = "Adds the 9GAG watermark to an image";
|
||||
static aliases = ["ninegag", "gag"];
|
||||
|
||||
static noImage = "you need to provide an image to add a 9GAG watermark!";
|
||||
static command = "watermark";
|
||||
}
|
||||
|
||||
module.exports = NineGagCommand;
|
17
commands/image-editing/bandicam.js
Normal file
17
commands/image-editing/bandicam.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const ImageCommand = require("../../classes/imageCommand.js");
|
||||
|
||||
class BandicamCommand extends ImageCommand {
|
||||
params = {
|
||||
water: "./assets/images/bandicam.png",
|
||||
gravity: 2,
|
||||
resize: true
|
||||
};
|
||||
|
||||
static description = "Adds the Bandicam watermark to an image";
|
||||
static aliases = ["bandi"];
|
||||
|
||||
static noImage = "you need to provide an image to add a Bandicam watermark!";
|
||||
static command = "watermark";
|
||||
}
|
||||
|
||||
module.exports = BandicamCommand;
|
14
commands/image-editing/blur.js
Normal file
14
commands/image-editing/blur.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
const ImageCommand = require("../../classes/imageCommand.js");
|
||||
|
||||
class BlurCommand extends ImageCommand {
|
||||
params = {
|
||||
sharp: false
|
||||
};
|
||||
|
||||
static description = "Blurs an image";
|
||||
|
||||
static noImage = "you need to provide an image to blur!";
|
||||
static command = "blur";
|
||||
}
|
||||
|
||||
module.exports = BlurCommand;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue