Initial commit
This commit is contained in:
commit
c33a86eb4c
132 changed files with 5860 additions and 0 deletions
7
utils/client.js
Normal file
7
utils/client.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// separate the client from app.js so we can call it later
|
||||
const { Client } = require("eris");
|
||||
const config = require("../config.json");
|
||||
const client = new Client(config.token, {
|
||||
defaultImageSize: 1024
|
||||
});
|
||||
module.exports = client;
|
||||
4
utils/collections.js
Normal file
4
utils/collections.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
const { Collection } = require("eris");
|
||||
|
||||
exports.commands = new Collection();
|
||||
exports.aliases = new Collection();
|
||||
6
utils/database.js
Normal file
6
utils/database.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// database stuff
|
||||
const Enmap = require("enmap");
|
||||
const settings = new Enmap({ name: "settings" });
|
||||
exports.settings = settings;
|
||||
const tags = new Enmap({ name: "tags" });
|
||||
exports.tags = tags;
|
||||
10
utils/dbl.js
Normal file
10
utils/dbl.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// dbl api client
|
||||
const DBL = require("dblapi.js");
|
||||
const logger = require("./logger.js");
|
||||
const config = require("../config.json");
|
||||
const client = require("./client.js");
|
||||
const dbl = new DBL(config.dblToken, client);
|
||||
dbl.on("error", e => {
|
||||
logger.error(e);
|
||||
});
|
||||
module.exports = dbl;
|
||||
15
utils/gmbuffer.js
Normal file
15
utils/gmbuffer.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// workaround for a gm bug where it doesn't output buffers properly
|
||||
// https://github.com/aheckmann/gm/issues/572#issuecomment-293768810
|
||||
module.exports = (data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
data.stream((err, stdout, stderr) => {
|
||||
if (err) return reject(err);
|
||||
const chunks = [];
|
||||
stdout.on("data", (chunk) => { chunks.push(chunk); });
|
||||
// these are 'once' because they can and do fire multiple times for multiple errors,
|
||||
// but this is a promise so you'll have to deal with them one at a time
|
||||
stdout.once("end", () => { resolve(Buffer.concat(chunks)); });
|
||||
stderr.once("data", (data) => { reject(String(data)); });
|
||||
});
|
||||
});
|
||||
};
|
||||
31
utils/handler.js
Normal file
31
utils/handler.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
const collections = require("./collections.js");
|
||||
|
||||
exports.load = async (command) => {
|
||||
const props = require(`../commands/${command}`);
|
||||
collections.commands.set(command.split(".")[0], props.run);
|
||||
if (props.aliases) {
|
||||
props.aliases.forEach(alias => {
|
||||
collections.aliases.set(alias, command.split(".")[0]);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.unload = async (command) => {
|
||||
let cmd;
|
||||
if (collections.commands.has(command)) {
|
||||
cmd = collections.commands.get(command);
|
||||
} else if (collections.aliases.has(command)) {
|
||||
cmd = collections.commands.get(collections.aliases.get(command));
|
||||
}
|
||||
if (!cmd) return `The command \`${command}\` doesn't seem to exist, nor is it an alias.`;
|
||||
const mod = require.cache[require.resolve(`../commands/${command}`)];
|
||||
delete require.cache[require.resolve(`../commands/${command}.js`)];
|
||||
for (let i = 0; i < mod.parent.children.length; i++) {
|
||||
if (mod.parent.children[i] === mod) {
|
||||
mod.parent.children.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
57
utils/imagedetect.js
Normal file
57
utils/imagedetect.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
const fetch = require("node-fetch");
|
||||
const fileType = require("file-type");
|
||||
|
||||
// this checks if the file is, in fact, an image
|
||||
const typeCheck = async (image) => {
|
||||
// download the file to a buffer
|
||||
const imageRequest = await fetch(image);
|
||||
const imageBuffer = await imageRequest.buffer();
|
||||
try {
|
||||
// get the file type
|
||||
const imageType = fileType(imageBuffer);
|
||||
// check if the file is a jpeg, png, or webp
|
||||
if (imageType && ["image/jpeg", "image/png", "image/webp"].includes(imageType.mime)) {
|
||||
// if it is, then return the url with the file type
|
||||
return {
|
||||
type: imageType.ext,
|
||||
url: image
|
||||
};
|
||||
} else {
|
||||
// if not, then return a message
|
||||
return "Not the correct file type";
|
||||
}
|
||||
} catch (error) {
|
||||
if (error) console.error;
|
||||
}
|
||||
};
|
||||
|
||||
// this checks for the latest message containing an image and returns the url of the image
|
||||
module.exports = async (cmdMessage) => {
|
||||
// we start by getting the messages
|
||||
const messages = await cmdMessage.channel.getMessages();
|
||||
// iterate over each message
|
||||
for (const message of messages) {
|
||||
// check the attachments first
|
||||
if (message.attachments.length !== 0) {
|
||||
// get type of file
|
||||
const type = await typeCheck(message.attachments[0].url);
|
||||
// move to the next message if the file isn't an image
|
||||
if (type === "Not the correct file type") continue;
|
||||
// if the file is an image then return it
|
||||
return type;
|
||||
// if there's nothing in the attachments check the embeds next
|
||||
} else if (message.embeds.length !== 0) {
|
||||
// embeds can have 2 possible entries with images, we check the thumbnail first
|
||||
if (message.embeds[0].thumbnail) {
|
||||
const type = await typeCheck(message.embeds[0].thumbnail.url);
|
||||
if (type === "Not the correct file type") continue;
|
||||
return type;
|
||||
// if there isn't a thumbnail check the image area
|
||||
} else if (message.embeds[0].image) {
|
||||
const type = await typeCheck(message.embeds[0].image.url);
|
||||
if (type === "Not the correct file type") continue;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
18
utils/logger.js
Normal file
18
utils/logger.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
const moment = require("moment");
|
||||
const winston = require("winston");
|
||||
const logger = winston.createLogger({
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
new winston.transports.File({ filename: "logs/error.log", level: "error" }),
|
||||
new winston.transports.File({ filename: "logs/main.log" }),
|
||||
],
|
||||
format: winston.format.printf(log => `[${moment().format("YYYY-MM-DD HH:mm:ss")}]: [${log.level.toUpperCase()}] - ${log.message}`)
|
||||
});
|
||||
|
||||
exports.log = (type = "info", content) => logger.log(type, content);
|
||||
|
||||
exports.error = (...args) => this.log("error", ...args);
|
||||
|
||||
exports.warn = (...args) => this.log("warn", ...args);
|
||||
|
||||
exports.debug = (...args) => this.log("debug", ...args);
|
||||
12
utils/meme.sh
Normal file
12
utils/meme.sh
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
newfile=$(mktemp /tmp/XXXXXXXXXXXXXXXXXXXXXX.png)
|
||||
convert - -resize 600x600 +profile "*" $newfile
|
||||
SIZE=$(identify -format "%[fx:w]x%[fx:h]" $newfile)
|
||||
convert $newfile \
|
||||
-gravity north \
|
||||
\( -size $SIZE -background none -font "./assets/ImpactMix.ttf" -pointsize 50 -stroke black -strokewidth 3 caption:"$1" \) -composite \
|
||||
\( -size $SIZE -background none -font "./assets/ImpactMix.ttf" -pointsize 50 -fill white -stroke none caption:"$1" \) -composite \
|
||||
-gravity south \
|
||||
\( -size $SIZE -background none -font "./assets/ImpactMix.ttf" -pointsize 50 -stroke black -strokewidth 3 caption:"$2" \) -composite \
|
||||
\( -size $SIZE -background none -font "./assets/ImpactMix.ttf" -pointsize 50 -fill white -stroke none caption:"$2" \) -composite\
|
||||
-
|
||||
rm $newfile
|
||||
41
utils/misc.js
Normal file
41
utils/misc.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// random(array) to select a random entry in array
|
||||
exports.random = (array) => {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
};
|
||||
|
||||
// clean(text) to clean message of any private info or mentions
|
||||
exports.clean = async (text) => {
|
||||
const config = require("../config.json");
|
||||
if (text && text.constructor.name == "Promise")
|
||||
text = await text;
|
||||
if (typeof evaled !== "string")
|
||||
text = require("util").inspect(text, { depth: 1 });
|
||||
|
||||
text = text
|
||||
.replace(/`/g, `\`${String.fromCharCode(8203)}`)
|
||||
.replace(/@/g, `@${String.fromCharCode(8203)}`)
|
||||
.replace(config.token, "<redacted>")
|
||||
.replace(config.mashapeKey, "<redacted>")
|
||||
.replace(config.catToken, "<redacted>")
|
||||
.replace(config.googleKey, "<redacted>")
|
||||
.replace(config.cseID, "<redacted>")
|
||||
.replace(config.dblToken, "<redacted>");
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
// regexEscape(string) to escape characters in a string for use in a regex
|
||||
exports.regexEscape = (string) => {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
|
||||
};
|
||||
|
||||
// define defaults for prefixes and tags
|
||||
exports.defaults = {
|
||||
prefix: "&"
|
||||
};
|
||||
exports.tagDefaults = {
|
||||
help: {
|
||||
content: "https://essem.space/esmBot/commands.html?dev=true",
|
||||
author: "198198681982205953"
|
||||
}
|
||||
};
|
||||
36
utils/pagination/awaitmessages.js
Normal file
36
utils/pagination/awaitmessages.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// eris doesn't come with an awaitMessages method by default, so we make our own
|
||||
const EventEmitter = require("events").EventEmitter;
|
||||
class MessageCollector extends EventEmitter {
|
||||
constructor(channel, filter, options = {}) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.channel = channel;
|
||||
this.options = options;
|
||||
this.ended = false;
|
||||
this.collected = [];
|
||||
this.bot = channel.guild ? channel.guild.shard.client : channel._client;
|
||||
this.listener = message => this.verify(message);
|
||||
this.bot.on("messageCreate", this.listener);
|
||||
if (options.time) setTimeout(() => this.stop("time"), options.time);
|
||||
}
|
||||
|
||||
verify(message) {
|
||||
if (this.channel.id !== message.channel.id) return false;
|
||||
if (this.filter(message)) {
|
||||
this.collected.push(message);
|
||||
this.emit("message", message);
|
||||
if (this.collected.length >= this.options.maxMatches) this.stop("maxMatches");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
stop(reason) {
|
||||
if (this.ended) return;
|
||||
this.ended = true;
|
||||
this.bot.removeListener("messageCreate", this.listener);
|
||||
this.emit("end", this.collected, reason);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageCollector;
|
||||
36
utils/pagination/awaitreactions.js
Normal file
36
utils/pagination/awaitreactions.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// eris doesn't come with an awaitReactions method by default, so we make our own
|
||||
const EventEmitter = require("events").EventEmitter;
|
||||
class ReactionCollector extends EventEmitter {
|
||||
constructor(message, filter, options = {}) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.message = message;
|
||||
this.options = options;
|
||||
this.ended = false;
|
||||
this.collected = [];
|
||||
this.bot = message.channel.guild ? message.channel.guild.shard.client : message.channel._client;
|
||||
this.listener = (message, emoji, userID) => this.verify(message, emoji, userID);
|
||||
this.bot.on("messageReactionAdd", this.listener);
|
||||
if (options.time) setTimeout(() => this.stop("time"), options.time);
|
||||
}
|
||||
|
||||
verify(message, emoji, userID) {
|
||||
if (this.message.id !== message.id) return false;
|
||||
if (this.filter(message, emoji, userID)) {
|
||||
this.collected.push({ message: message, emoji: emoji, userID: userID });
|
||||
this.emit("reaction", message, emoji, userID);
|
||||
if (this.collected.length >= this.options.maxMatches) this.stop("maxMatches");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
stop(reason) {
|
||||
if (this.ended) return;
|
||||
this.ended = true;
|
||||
this.bot.removeListener("messageReactionAdd", this.listener);
|
||||
this.emit("end", this.collected, reason);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReactionCollector;
|
||||
49
utils/pagination/pagination.js
Normal file
49
utils/pagination/pagination.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
const ReactionCollector = require("./awaitreactions.js");
|
||||
const MessageCollector = require("./awaitmessages.js");
|
||||
const client = require("../client.js");
|
||||
|
||||
const paginationEmbed = async (message, pages, timeout = 120000) => {
|
||||
let page = 0;
|
||||
pages[page].embed.footer.text = `Page ${page + 1} of ${pages.length}`;
|
||||
const currentPage = await message.channel.createMessage(pages[page]);
|
||||
const emojiList = ["◀", "🔢", "▶", "🗑"];
|
||||
for (const emoji of emojiList) {
|
||||
await currentPage.addReaction(emoji);
|
||||
}
|
||||
const reactionCollector = new ReactionCollector(currentPage, (message, reaction, user) => emojiList.includes(reaction.name) && !client.users.get(user).bot, { time: timeout });
|
||||
reactionCollector.on("reaction", (msg, reaction) => {
|
||||
//reaction.users.remove(msg.author);
|
||||
//const reactionAuthor = currentPage.getReactions();
|
||||
switch (reaction.name) {
|
||||
case "◀":
|
||||
page = page > 0 ? --page : pages.length - 1;
|
||||
pages[page].embed.footer.text = `Page ${page + 1} of ${pages.length}`;
|
||||
currentPage.edit(pages[page]);
|
||||
break;
|
||||
case "🔢":
|
||||
message.channel.createMessage(`${message.author.mention}, what page do you want to jump to?`).then(askMessage => {
|
||||
const messageCollector = new MessageCollector(askMessage.channel, (response) => response.author.id === message.author.id && !isNaN(response.content) && Number(response.content) <= pages.length, { time: timeout, maxMatches: 1 });
|
||||
return messageCollector.on("message", response => {
|
||||
askMessage.delete();
|
||||
page = Number(response.content) - 1;
|
||||
pages[page].embed.footer.text = `Page ${page + 1} of ${pages.length}`;
|
||||
currentPage.edit(pages[page]);
|
||||
});
|
||||
}).catch(error => { if (error) console.error; });
|
||||
break;
|
||||
case "▶":
|
||||
page = page + 1 < pages.length ? ++page : 0;
|
||||
pages[page].embed.footer.text = `Page ${page + 1} of ${pages.length}`;
|
||||
currentPage.edit(pages[page]);
|
||||
break;
|
||||
case "🗑":
|
||||
currentPage.delete();
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
reactionCollector.on("end", () => currentPage.removeReactions());
|
||||
return currentPage;
|
||||
};
|
||||
module.exports = paginationEmbed;
|
||||
23
utils/soundplayer.js
Normal file
23
utils/soundplayer.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const client = require("./client.js");
|
||||
|
||||
module.exports = async (sound, message) => {
|
||||
if (message.member.voiceState.channelID) {
|
||||
if (!message.channel.guild.members.get(client.user.id).permission.has("voiceConnect") || !message.channel.permissionsOf(client.user.id).has("voiceConnect")) return client.createMessage(message.channel.id, `${message.author.mention}, I can't join this voice channel!`);
|
||||
const voiceChannel = message.channel.guild.channels.get(message.member.voiceState.channelID);
|
||||
client.createMessage(message.channel.id, "🔊 Playing sound...");
|
||||
const connection = await client.joinVoiceChannel(voiceChannel.id);
|
||||
if (connection.playing) {
|
||||
connection.stopPlaying();
|
||||
}
|
||||
connection.play(require("fs").createReadStream(sound));
|
||||
connection.on("error", (error) => {
|
||||
voiceChannel.leave();
|
||||
require("./logger.js").error(error);
|
||||
});
|
||||
connection.once("end", () => {
|
||||
voiceChannel.leave();
|
||||
});
|
||||
} else {
|
||||
client.createMessage(message.channel.id, `${message.author.mention}, you need to be in a voice channel first!`);
|
||||
}
|
||||
};
|
||||
16
utils/urlcheck.js
Normal file
16
utils/urlcheck.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module.exports = (string) => {
|
||||
var protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
|
||||
var domainRE = /^[^\s.]+\.\S{2,}$/;
|
||||
var match = string.match(protocolAndDomainRE);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
var everythingAfterProtocol = match[1];
|
||||
if (!everythingAfterProtocol) {
|
||||
return false;
|
||||
}
|
||||
if (domainRE.test(everythingAfterProtocol)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
12
utils/wrap.js
Normal file
12
utils/wrap.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
module.exports = (str) => {
|
||||
var regexString = ".{1,15}([\\s\u200B]+|$)|[^\\s\u200B]+?([\\s\u200B]+|$)";
|
||||
var re = new RegExp(regexString, "g");
|
||||
var lines = str.match(re) || [];
|
||||
var result = lines.map((line) => {
|
||||
if (line.slice(-1) === "\n") {
|
||||
line = line.slice(0, line.length - 1);
|
||||
}
|
||||
return line;
|
||||
}).join("\n");
|
||||
return result;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue