From 16927d866704c807c95a1136595257df3c6aa1dc Mon Sep 17 00:00:00 2001 From: TheEssem Date: Fri, 29 Nov 2019 20:00:14 -0600 Subject: [PATCH] Don't load commands if env variable doesn't exist, removed catfact/dogfact, many other changes --- .env.example | 25 +++++++++++-- app.js | 10 ++--- commands/addtweet.js | 4 +- commands/cat.js | 2 + commands/catfact.js | 10 ----- commands/dogfact.js | 10 ----- commands/image.js | 2 + commands/mc.js | 2 +- commands/tweet.js | 4 +- commands/wikihow.js | 4 +- commands/yoda.js | 2 +- commands/youtube.js | 4 +- package-lock.json | 8 ++++ package.json | 1 + utils/collections.js | 1 - utils/gmbuffer.js | 68 +++++++++++++++++----------------- utils/handler.js | 8 ++++ utils/misc.js | 19 +++++++--- utils/pagination/pagination.js | 8 +++- utils/soundplayer.js | 7 +--- 20 files changed, 116 insertions(+), 83 deletions(-) delete mode 100644 commands/catfact.js delete mode 100644 commands/dogfact.js diff --git a/.env.example b/.env.example index 4c22a05..312a5ac 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,18 @@ -# Put MongoDB database URL here -MONGO= +########### +# Required +########### # Put Discord token here TOKEN= +# Put MongoDB database URL here +MONGO=mongodb://localhost:27017/esmBot +# Put snowflake ID of bot owner here +OWNER= + +########### +# Optional +########### + # Put Cat API token here CAT= # Put Mashape/RapidAPI key here @@ -14,5 +24,12 @@ CSE= # Put DBL/top.gg token here DBL= -# Put snowflake ID of bot owner here -OWNER= \ No newline at end of file +# Enable/disable Twitter bot (true/false) +TWITTER=false +# Put Twitter username here +HANDLE= +# Put consumer key, consumer secret, access token, and access secret here +TWITTER_KEY= +CONSUMER_SECRET= +ACCESS_TOKEN= +ACCESS_SECRET= \ No newline at end of file diff --git a/app.js b/app.js index b74fec4..aedce7b 100644 --- a/app.js +++ b/app.js @@ -20,24 +20,24 @@ async function init() { // register commands const commands = await readdir("./commands/"); logger.log("info", `Attempting to load ${commands.length} commands...`); - commands.forEach(commandFile => { + for (const commandFile of commands) { logger.log("info", `Loading command ${commandFile}...`); try { - handler.load(commandFile); + await handler.load(commandFile); } catch (e) { logger.error(`Failed to register command ${commandFile.split(".")[0]}: ${e}`); } - }); + } // register events const events = await readdir("./events/"); logger.log("info", `Attempting to load ${events.length} events...`); - events.forEach(file => { + 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); - }); + } // login client.connect(); diff --git a/commands/addtweet.js b/commands/addtweet.js index f10220b..ddbe327 100644 --- a/commands/addtweet.js +++ b/commands/addtweet.js @@ -10,4 +10,6 @@ exports.run = async (message, args) => { return `${message.author.mention}, the content has been added.`; }; -exports.aliases = ["add"]; \ No newline at end of file +exports.aliases = ["add"]; + +exports.requires = "twitter"; \ No newline at end of file diff --git a/commands/cat.js b/commands/cat.js index b3489dc..acf941d 100644 --- a/commands/cat.js +++ b/commands/cat.js @@ -19,3 +19,5 @@ exports.run = async (message) => { }; exports.aliases = ["kitters", "kitties", "kitty", "cattos", "catto", "cats"]; + +exports.requires = "cat"; \ No newline at end of file diff --git a/commands/catfact.js b/commands/catfact.js deleted file mode 100644 index 0e48cf7..0000000 --- a/commands/catfact.js +++ /dev/null @@ -1,10 +0,0 @@ -const fetch = require("node-fetch"); - -exports.run = async (message) => { - message.channel.sendTyping(); - const imageData = await fetch("https://catfact.ninja/fact"); - const json = await imageData.json(); - return `🐱 **Did you know?** ${json.fact}`; -}; - -exports.aliases = ["kittyfact"]; diff --git a/commands/dogfact.js b/commands/dogfact.js deleted file mode 100644 index b6dbe41..0000000 --- a/commands/dogfact.js +++ /dev/null @@ -1,10 +0,0 @@ -const fetch = require("node-fetch"); - -exports.run = async (message) => { - message.channel.sendTyping(); - const imageData = await fetch("https://dog-api.kinduff.com/api/facts"); - const json = await imageData.json(); - return `🐶 **Did you know?** ${json.facts[0]}`; -}; - -exports.aliases = ["pupfact"]; diff --git a/commands/image.js b/commands/image.js index 4437e86..7370152 100644 --- a/commands/image.js +++ b/commands/image.js @@ -32,3 +32,5 @@ exports.run = async (message, args) => { }; exports.aliases = ["im", "photo", "img"]; + +exports.requires = "google"; \ No newline at end of file diff --git a/commands/mc.js b/commands/mc.js index 92f164c..454c5c6 100644 --- a/commands/mc.js +++ b/commands/mc.js @@ -3,7 +3,7 @@ const fetch = require("node-fetch"); exports.run = async (message, args) => { if (args.length === 0) return `${message.author.mention}, you need to provide some text to generate a Minecraft achievement!`; message.channel.sendTyping(); - const request = await fetch(`https://www.minecraftskinstealer.com/achievement/a.php?i=13&h=Achievement+get%21&t=${args.join("+")}`); + const request = await fetch(`https://www.minecraftskinstealer.com/achievement/a.php?i=13&h=Achievement+get%21&t=${encodeURIComponent(args.join("+"))}`); const buffer = await request.buffer(); return message.channel.createMessage("", { file: buffer, diff --git a/commands/tweet.js b/commands/tweet.js index 4682f62..74f3cf2 100644 --- a/commands/tweet.js +++ b/commands/tweet.js @@ -6,4 +6,6 @@ exports.run = async (message, args) => { const info = await twitter.client.post("statuses/update", { status: args.join(" ") }); if (info.resp.statusCode !== 200) return `Something happened when trying to post this tweet: ${info.resp.statusCode} ${info.resp.statusMessage}`; return `${message.author.mention}, a tweet with id ${info.data.id_str} has been posted with status code ${info.resp.statusCode} ${info.resp.statusMessage}.`; -}; \ No newline at end of file +}; + +exports.requires = "twitter"; \ No newline at end of file diff --git a/commands/wikihow.js b/commands/wikihow.js index 7812b5b..91dd154 100644 --- a/commands/wikihow.js +++ b/commands/wikihow.js @@ -17,4 +17,6 @@ exports.run = async (message) => { }); }; -exports.aliases = ["wiki"]; \ No newline at end of file +exports.aliases = ["wiki"]; + +exports.requires = "mashape"; \ No newline at end of file diff --git a/commands/yoda.js b/commands/yoda.js index 6177f3a..47c21cb 100644 --- a/commands/yoda.js +++ b/commands/yoda.js @@ -2,7 +2,7 @@ const fetch = require("node-fetch"); exports.run = async (message, args) => { if (args.length === 0) return `${message.author.mention}, you need to provide some text to translate to Yodish!`; - const request = await fetch(`https://yoda-api.appspot.com/api/v1/yodish?text=${args.join("%20")}`); + const request = await fetch(`https://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(args.join(" "))}`); const json = await request.json(); return json.yodish; }; diff --git a/commands/youtube.js b/commands/youtube.js index bd4e1ee..f13dee4 100644 --- a/commands/youtube.js +++ b/commands/youtube.js @@ -17,4 +17,6 @@ exports.run = async (message, args) => { } }; -exports.aliases = ["yt", "video", "ytsearch"]; \ No newline at end of file +exports.aliases = ["yt", "video", "ytsearch"]; + +exports.requires = "google"; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5c504e2..ead9736 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1710,6 +1710,14 @@ "minimist": "0.0.8" } }, + "mmmagic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mmmagic/-/mmmagic-0.5.3.tgz", + "integrity": "sha512-xLqCu7GJYTzJczg0jafXFuh+iPzQL/ru0YYf4GiTTz8Cehru/wiXtUS8Pp8Xi77zNaiVndJ0OO1yAFci6iHyFg==", + "requires": { + "nan": "^2.13.2" + } + }, "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", diff --git a/package.json b/package.json index 4ad57f3..6396860 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "gm": "^1.23.1", "googleapis": "^44.0.0", "jsqr": "^1.2.0", + "mmmagic": "^0.5.3", "moment": "^2.24.0", "moment-duration-format": "^2.3.2", "mongoose": "^5.7.10", diff --git a/utils/collections.js b/utils/collections.js index b9108cb..edcd292 100644 --- a/utils/collections.js +++ b/utils/collections.js @@ -2,4 +2,3 @@ const { Collection } = require("eris"); exports.commands = new Collection(); exports.aliases = new Collection(); -exports.voiceConnections = new Collection(); diff --git a/utils/gmbuffer.js b/utils/gmbuffer.js index be17a24..17bcfc0 100644 --- a/utils/gmbuffer.js +++ b/utils/gmbuffer.js @@ -1,39 +1,37 @@ // workaround for a gm bug where it doesn't output buffers properly // https://github.com/aheckmann/gm/issues/572#issuecomment-293768810 -module.exports = (data, format) => { - return new Promise((resolve, reject) => { - if (format) { - data.stream(format, (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)); - }); +module.exports = async (data, format) => { + if (format) { + data.stream(format, (err, stdout, stderr) => { + if (err) throw err; + const chunks = []; + stdout.on("data", (chunk) => { + chunks.push(chunk); }); - } else { - 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)); - }); + // 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", () => { + return Buffer.concat(chunks); }); - } - }); -}; + stderr.once("data", (data) => { + throw data; + }); + }); + } else { + data.stream((err, stdout, stderr) => { + if (err) throw 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", () => { + return Buffer.concat(chunks); + }); + stderr.once("data", (data) => { + throw data; + }); + }); + } +}; \ No newline at end of file diff --git a/utils/handler.js b/utils/handler.js index ff154c8..c5bcef9 100644 --- a/utils/handler.js +++ b/utils/handler.js @@ -1,8 +1,15 @@ const collections = require("./collections.js"); +const logger = require("./logger.js"); +// load command into memory exports.load = async (command) => { const props = require(`../commands/${command}`); + if (props.requires === "google" && process.env.GOOGLE === "") return logger.log("info", `Google info not provided in config, skipped loading command ${command}...`); + if (props.requires === "cat" && process.env.CAT === "") return logger.log("info", `Cat API info not provided in config, skipped loading command ${command}...`); + if (props.requires === "mashape" && process.env.MASHAPE === "") return logger.log("info", `Mashape/RapidAPI info not provided in config, skipped loading command ${command}...`); + if (props.requires === "twitter" && process.env.TWITTER === "false") return logger.log("info", `Twitter bot disabled, skipped loading command ${command}...`); collections.commands.set(command.split(".")[0], props.run); + // add each alias to if (props.aliases) { props.aliases.forEach(alias => { collections.aliases.set(alias, command.split(".")[0]); @@ -11,6 +18,7 @@ exports.load = async (command) => { return false; }; +// unload command from memory exports.unload = async (command) => { let cmd; if (collections.commands.has(command)) { diff --git a/utils/misc.js b/utils/misc.js index 5ed0951..6583cde 100644 --- a/utils/misc.js +++ b/utils/misc.js @@ -32,12 +32,21 @@ exports.clean = async (text) => { exports.getTweet = async (tweets, reply = false, isDownload = false) => { const randomTweet = this.random(reply ? (isDownload ? tweets.download : tweets.replies) : tweets.tweets); if (randomTweet.match("{{message}}")) { - return randomTweet.replace(/{{message}}/g, await this.getRandomMessage()); + return randomTweet.replace(/{{message}}/gm, await this.getRandomMessage()); } else { - return randomTweet.replace(/{{media}}/g, this.random(tweets.media)) - .replace(/{{games}}/g, this.random(tweets.games)) - .replace(/{{phrases}}/g, this.random(tweets.phrases)) - .replace(/{{characters}}/g, this.random(tweets.characters)); + return randomTweet + .replace(/{{media}}/gm, () => { + return this.random(tweets.media); + }) + .replace(/{{games}}/gm, () => { + return this.random(tweets.games); + }) + .replace(/{{phrases}}/gm, () => { + return this.random(tweets.phrases); + }) + .replace(/{{characters}}/gm, () => { + return this.random(tweets.characters); + }); } }; diff --git a/utils/pagination/pagination.js b/utils/pagination/pagination.js index 6a8ebc5..d306d4f 100644 --- a/utils/pagination/pagination.js +++ b/utils/pagination/pagination.js @@ -52,7 +52,13 @@ const paginationEmbed = async (message, pages, timeout = 120000) => { } } }); - reactionCollector.on("end", () => currentPage.removeReactions()); + reactionCollector.on("end", () => { + try { + currentPage.removeReactions(); + } catch (e) { + console.log("Reaction message was deleted"); + } + }); return currentPage; }; module.exports = paginationEmbed; diff --git a/utils/soundplayer.js b/utils/soundplayer.js index 49da38f..c888913 100644 --- a/utils/soundplayer.js +++ b/utils/soundplayer.js @@ -1,23 +1,19 @@ const client = require("./client.js"); const fs = require("fs"); const logger = require("./logger.js"); -const connections = require("./collections.js").voiceConnections; 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); if (!voiceChannel.permissionsOf(client.user.id).has("voiceConnect")) return client.createMessage(message.channel.id, `${message.author.mention}, I don't have permission to join this voice channel!`); - const checkConnection = connections.get(message.channel.guild.id); - const connection = checkConnection ? checkConnection : await voiceChannel.join(); + const connection = await voiceChannel.join(); const playingMessage = await client.createMessage(message.channel.id, "🔊 Playing sound..."); - connections.set(message.channel.guild.id, connection); if (connection.playing) { connection.stopPlaying(); } connection.play(fs.createReadStream(sound)); connection.on("error", (error) => { - connections.delete(message.channel.guild.id); voiceChannel.leave(); playingMessage.delete(); logger.error(error); @@ -26,7 +22,6 @@ module.exports = async (sound, message) => { logger.warn(warn); }); connection.once("end", () => { - connections.delete(message.channel.guild.id); voiceChannel.leave(); playingMessage.delete(); });