diff --git a/commands/ban.js b/commands/ban.js index 43e5918d..b3412c61 100644 --- a/commands/ban.js +++ b/commands/ban.js @@ -23,7 +23,7 @@ module.exports = { if(mentionHighestRole >= authorHighestRole) return message.channel.send("You can't ban members with an equal or higher position than you."); if(!mentionedUser.bannable) return message.channel.send("I can't ban this user."); - mentionedUser.send(`🔨 You were banned from **${message.guild.name}**${(banReason !== "no reason specified") ? `, for ${banReason}.` : "."}`) + mentionedUser.send(`🔨 Hi! You got banned from **${message.guild.name}**${(banReason !== "no reason specified") ? ` for ${banReason}.` : "."}`) .then(() => iHateThis()) .catch(() => iHateThis()); diff --git a/commands/clean.js b/commands/clean.js index 80950d2e..65f321a3 100644 --- a/commands/clean.js +++ b/commands/clean.js @@ -17,7 +17,7 @@ module.exports = { if(parseInt(args[0]) < 1 || isNaN(parseInt(args[0]))) return message.channel.send(embeds.errorEmbed("You're so funny! But to eat messages, I need the amount of messages you want me to eat **in numbers** - and it should be greater than or equal to **1**.")); if(parseInt(args[0]) > 99) return message.channel.send(embeds.errorEmbed("Sorry, I can only eat 99 messages at a time.")); - message.channel.bulkDelete(parseInt(args[0]) + 1).then(() => { + message.channel.bulkDelete(parseInt(args[0]) + 1, true).then(() => { message.channel.send(format(vukkytils.getString("CLEANED_MESSAGES"), args[0])).then(msg => msg.delete({timeout: 2000})); }); }, diff --git a/commands/covid19.js b/commands/covid19.js index d8d2a2a1..f9d55883 100644 --- a/commands/covid19.js +++ b/commands/covid19.js @@ -27,6 +27,7 @@ module.exports = { } }) .then(json => { + if(!json) return; newMessage.edit(format(vukkytils.getString("API_CREDIT"), "https://disease.sh"), embeds.covidEmbed(country ? json.countryInfo.flag : null, country ? json.country : "Global", commaNumber(json.cases), commaNumber(json.todayCases), commaNumber(json.deaths), commaNumber(json.todayDeaths), commaNumber(json.recovered), commaNumber(json.todayRecovered), commaNumber(json.active), commaNumber(json.critical), commaNumber(json.tests))); }); }); diff --git a/commands/emoji.js b/commands/emoji.js index 0d793746..d96b591a 100644 --- a/commands/emoji.js +++ b/commands/emoji.js @@ -16,9 +16,9 @@ module.exports = { if (args[1].length >= 2) { let RegExp = /[^a-z^A-Z^0-9]/gm; if (!RegExp.test(args[1])) { - message.guild.emojis.create((message.attachments).array()[0].url, args[1]) - .then(emoji => message.channel.send(successEmbed(`Created new emoji with name ${emoji.name}`))) - .catch(error => message.channel.send(errorEmbed(`Error: ${error.message}`))); + message.guild.emojis.create((message.attachments).array()[0].url, args[1], { reason: `Done by ${message.author.tag}` }) + .then(emoji => message.channel.send(successEmbed(`I've made a new emoji called ${emoji.name}!`))) + .catch(error => message.channel.send(errorEmbed(`${error.message}`))); } else { message.channel.send(errorEmbed("I found symbols that are not suitable for the name of the emoji!")); } @@ -32,11 +32,11 @@ module.exports = { message.channel.send(errorEmbed("You didn't give me enough arguments!\nUsage:`emoji add ` with an image as attachment.")); } } else { - if (args[0] == "delete") { + if (args[0] == "delete" || args[0] == "remove") { if(!message.guild.emojis.cache.get(args[1])) return message.channel.send(embeds.errorEmbed(`\`${args[1]}\` is not an emoji ID.`)); let emoji = message.guild.emojis.cache.get(args[1]); emoji.delete({ reason: `Done by ${message.author.tag}` }); - message.channel.send(embeds.successEmbed(`\`${emoji.name}\` has been deleted!`)); + message.channel.send(embeds.successEmbed(`I've deleted \`${emoji.name}\`!`)); } else { return message.channel.send(embeds.errorEmbed(`${args[0]} is not supported for this command.`)); } diff --git a/commands/help.js b/commands/help.js index e05bfeb3..877a6df4 100644 --- a/commands/help.js +++ b/commands/help.js @@ -39,9 +39,9 @@ module.exports = { const helpEmbed = new Discord.MessageEmbed() .setColor("#4b83c3") .setTitle(`ℹ ${command.name}`) - .setDescription(command.description) + .setDescription(command.description || vukkytils.getString("HELP_NO_DESCRIPTION")) .setTimestamp() - .setFooter(embeds.versionString, embeds.avatarURL); + .setFooter(embeds.versionString, embeds.getAvatarURL()); if (command.aliases) helpEmbed.addField(vukkytils.getString("HELP_ALIASES"), `${command.aliases.join(", ")}`, true); if (command.usage) helpEmbed.addField(vukkytils.getString("HELP_USAGE"), `${prefix}${command.name} ${command.usage}`, true); diff --git a/commands/kick.js b/commands/kick.js index b355027d..e604bd11 100644 --- a/commands/kick.js +++ b/commands/kick.js @@ -23,7 +23,7 @@ module.exports = { if(mentionHighestRole >= authorHighestRole) return message.channel.send("You can't kick members with an equal or higher position than you."); if(!mentionedUser.kickable) return message.channel.send("I can't kick this user."); - mentionedUser.send(`👢 You were kicked from **${message.guild.name}**${(kickReason !== "no reason specified") ? `, for ${kickReason}.` : "."}`) + mentionedUser.send(`👢 Hi! You got kicked from **${message.guild.name}**${(kickReason !== "no reason specified") ? ` for ${kickReason}.` : "."}`) .then(() => iHateThis()) .catch(() => iHateThis()); diff --git a/commands/ohno.js b/commands/ohno.js index 0dbc2778..07f7c056 100644 --- a/commands/ohno.js +++ b/commands/ohno.js @@ -1,12 +1,17 @@ const canvacord = require("canvacord").Canvas; const Discord = require("discord.js"); +const config = require("../config.json"); module.exports = { name: "ohno", description: "oh no! it's stupid", botPermissions: ["ATTACH_FILES"], + args: true, + usage: "", async execute(message, args) { + await message.react(config.misc.emoji.loading); const ohno = await canvacord.ohno(args.slice(0).join(" ")); + await message.reactions.removeAll(); message.channel.send(new Discord.MessageAttachment(ohno, "ohno.png")); }, }; diff --git a/commands/opinion.js b/commands/opinion.js index 5d1c602d..86dcbb3a 100644 --- a/commands/opinion.js +++ b/commands/opinion.js @@ -1,12 +1,22 @@ const canvacord = require("canvacord").Canvas; const Discord = require("discord.js"); +const config = require("../config.json"); module.exports = { name: "opinion", description: "father's son makes an opinion", botPermissions: ["ATTACH_FILES"], + args: true, + usage: "[user] ", async execute(message, args) { - const opinion = await canvacord.opinion(message.author.avatarURL({ format: "png" }), args.slice(0).join(" ")); + await message.react(config.misc.emoji.loading); + let opinion; + if(message.mentions.users.size) { + opinion = await canvacord.opinion(message.mentions.users.first().avatarURL({ format: "png" }), args.slice(1).join(" ")); + } else { + opinion = await canvacord.opinion(message.author.avatarURL({ format: "png" }), args.slice(0).join(" ")); + } + await message.reactions.removeAll(); message.channel.send(new Discord.MessageAttachment(opinion, "opinion.png")); }, }; diff --git a/commands/rip.js b/commands/rip.js index c95b5433..a78b20ce 100644 --- a/commands/rip.js +++ b/commands/rip.js @@ -1,12 +1,21 @@ const canvacord = require("canvacord").Canvas; const Discord = require("discord.js"); +const config = require("../config.json"); module.exports = { name: "rip", description: "rip", botPermissions: ["ATTACH_FILES"], + usage: "[user]", async execute(message, args) { - const rip = await canvacord.rip(message.author.avatarURL({ format: "png" })); + await message.react(config.misc.emoji.loading); + let rip; + if(message.mentions.users.size) { + rip = await canvacord.rip(message.mentions.users.first().avatarURL({ format: "png" })); + } else { + rip = await canvacord.rip(message.author.avatarURL({ format: "png" })); + } + await message.reactions.removeAll(); message.channel.send(new Discord.MessageAttachment(rip, "rip.png")); }, }; diff --git a/commands/trash.js b/commands/trash.js index a0a89934..b280f935 100644 --- a/commands/trash.js +++ b/commands/trash.js @@ -1,12 +1,21 @@ const canvacord = require("canvacord").Canvas; const Discord = require("discord.js"); +const config = require("../config.json"); module.exports = { name: "trash", description: "trash?", botPermissions: ["ATTACH_FILES"], + usage: "[user]", async execute(message, args) { - const trash = await canvacord.trash(message.author.avatarURL({ format: "png" })); + await message.react(config.misc.emoji.loading); + let trash; + if(message.mentions.users.size) { + trash = await canvacord.trash(message.mentions.users.first().avatarURL({ format: "png" })); + } else { + trash = await canvacord.trash(message.author.avatarURL({ format: "png" })); + } + await message.reactions.removeAll(); message.channel.send(new Discord.MessageAttachment(trash, "trash.png")); }, }; diff --git a/commands/tweet.js b/commands/tweet.js index 02018ad1..c484643e 100644 --- a/commands/tweet.js +++ b/commands/tweet.js @@ -1,7 +1,8 @@ +/* eslint-disable no-inner-declarations */ // Copyright (C) 2021 Vukky, vtheskeleton const embeds = require("../utilities/embeds"); -const config = require("../config.json"); +const fetch = require("node-fetch"); require("dotenv").config(); var Twitter = require("twitter"); const vukkytils = require("../utilities/vukkytils"); @@ -13,40 +14,90 @@ module.exports = { botPermissions: ["EMBED_LINKS", "MANAGE_MESSAGES"], cooldown: 120, usage: "", + guildOnly: true, + aliases: ["twt", "tw"], execute(message, args) { - if(args.slice(0).join(" ").length > 280) return message.channel.send(embeds.errorEmbed("Sorry, but that tweet's too long.")); + let attachments = []; + if(message.attachments.first()) attachments = message.attachments.map(attachment => attachment.url); + const tweet = args.slice(0).join(" "); + delete require.cache[require.resolve("../config.json")]; + const config = require("../config.json"); + let selfdownvote = false; + if(config.commands.tweet.blacklist[message.author.id]) return message.channel.send(embeds.tweetBlacklistEmbed(config.commands.tweet.blacklist[message.author.id])); + if(tweet.length == 0 && attachments.length == 0) return message.channel.send(embeds.errorEmbed("That tweet is pretty empty!")); + if(tweet.length > 280) return message.channel.send(embeds.errorEmbed("Sorry, but that tweet's too long.")); + if(attachments.length > 1) return message.channel.send(embeds.errorEmbed("Only 1 attachment at a time is currently supported.")); message.react("⬆").then(() => message.react("⬇")); const filter = (reaction, user) => { - return ["⬆", "⬇"].includes(reaction.emoji.name) && user.id != message.author.id && user.bot == false; + if(user.bot) return false; + if(reaction.emoji.name == "⬆" && config.misc.owner.includes(user.id)) return true; + if(reaction.emoji.name == "⬆" && user.id == message.author.id) return false; + if(reaction.emoji.name == "⬆" && user.id != message.author.id) return true; + if(reaction.emoji.name == "⬇") { + if(user.id == message.author.id) selfdownvote = true; + return true; + } + return false; }; message.awaitReactions(filter, { max: 1 }) - .then(collected => { - message.reactions.removeAll(); + .then(async collected => { const reaction = collected.first(); + if(!reaction || !reaction.emoji || !reaction.emoji.name) return message.channel.send("could not get result"); if(reaction.emoji.name == "⬆") { + await message.reactions.removeAll(); + if(reaction.users.cache) console.log(`[twttr] tweet approved by ${reaction.users.cache.last().tag}: ${tweet}`); var client = new Twitter({ consumer_key: process.env.TWITTER_KEY, consumer_secret: process.env.TWITTER_SECRET, access_token_key: process.env.TWITTER_ACCESS, access_token_secret: process.env.TWITTER_ACCESS_SECRET }); - message.channel.send(`${config.misc.emoji.loading} ${vukkytils.getString("TWEETING")}`).then(tweeting => { - client.post("statuses/update", {status: args.slice(0).join(" ")}) - .then(function (tweet) { - tweeting.delete(); - message.react("✅"); + await message.react(config.misc.emoji.loading); + let status = { + status: tweet + }; + if(attachments.length == 1) { + await fetch(attachments[0]) + .then(res => res.buffer()) + .then(buffer => { + client.post("media/upload", {media: buffer}, async function(error, media) { + if (!error) { + status.media_ids = media.media_id_string; + post(); + } else { + console.error(error); + await message.reactions.removeAll(); + await message.react("❌"); + message.reply("there was an error!", embeds.errorEmbed(`${error.message ? error.message : "Unknown error."}`)); + } + }); + }); + } else { + post(); + } + function post() { + client.post("statuses/update", status) + .then(async function (tweet) { + await message.reactions.removeAll(); + await message.react("✅"); message.reply(format(vukkytils.getString("TWEET_APPROVED"), `https://twitter.com/i/status/${tweet.id_str}`)); }) - .catch(function (error) { - tweeting.delete(); - message.react("❌"); + .catch(async function (error) { + await message.reactions.removeAll(); + await message.react("❌"); message.reply("there was an error!", embeds.errorEmbed(`${error.message ? error.message : "Unknown error."}`)); throw error; }); - }); + } } else if (reaction.emoji.name == "⬇") { - message.react("❌"); - message.reply(vukkytils.getString("TWEET_DENIED")); + if(!selfdownvote) { + await message.reactions.removeAll(); + if(reaction.users.cache) console.log(`[twttr] tweet denied by ${reaction.users.cache.last().tag}: ${tweet}`); + await message.react("❌"); + message.reply(vukkytils.getString("TWEET_DENIED")); + } else { + message.delete(); + } } }); }, diff --git a/commands/tweetreply.js b/commands/tweetreply.js index 336daa2e..973cb95a 100644 --- a/commands/tweetreply.js +++ b/commands/tweetreply.js @@ -1,7 +1,8 @@ +/* eslint-disable no-inner-declarations */ // Copyright (C) 2021 Vukky, vtheskeleton const embeds = require("../utilities/embeds"); -const config = require("../config.json"); +const fetch = require("node-fetch"); require("dotenv").config(); var Twitter = require("twitter"); const { Util } = require("discord.js"); @@ -13,45 +14,95 @@ module.exports = { description: "Make VukkyBot reply to things on Twitter!", botPermissions: ["EMBED_LINKS", "MANAGE_MESSAGES"], cooldown: 120, - aliases: ["replytweet"], + aliases: ["replytweet", "twtr", "tweetr", "twr"], usage: " ", + guildOnly: true, execute(message, args) { - if(args.slice(1).join(" ").length > 280) return message.channel.send(embeds.errorEmbed("Sorry, but that tweet's too long.")); + let attachments = []; + if(message.attachments.first()) attachments = message.attachments.map(attachment => attachment.url); + const tweet = args.slice(1).join(" "); + delete require.cache[require.resolve("../config.json")]; + const config = require("../config.json"); + let selfdownvote = false; + if(config.commands.tweet.blacklist[message.author.id]) return message.channel.send(embeds.tweetBlacklistEmbed(config.commands.tweet.blacklist[message.author.id])); + if(tweet.length == 0 && attachments.length == 0) return message.channel.send(embeds.errorEmbed("That tweet is pretty empty!")); + if(tweet.length > 280) return message.channel.send(embeds.errorEmbed("Sorry, but that tweet's too long.")); if(isNaN(args[0])) return message.channel.send(embeds.errorEmbed("Your Tweet ID isn't a number!")); message.react("⬆").then(() => message.react("⬇")); const filter = (reaction, user) => { - return ["⬆", "⬇"].includes(reaction.emoji.name) && user.id != message.author.id && user.bot == false; + if(user.bot) return false; + if(reaction.emoji.name == "⬆" && config.misc.owner.includes(user.id)) return true; + if(reaction.emoji.name == "⬆" && user.id == message.author.id) return false; + if(reaction.emoji.name == "⬆" && user.id != message.author.id) return true; + if(reaction.emoji.name == "⬇") { + if(user.id == message.author.id) selfdownvote = true; + return true; + } + return false; }; message.reply(format(vukkytils.getString("TWEET_REPLYING_TO"), Util.removeMentions(`https://twitter.com/i/status/${args[0]}`))).then(tweetreplyDisclaimer => { message.awaitReactions(filter, { max: 1 }) - .then(collected => { - message.reactions.removeAll(); + .then(async collected => { tweetreplyDisclaimer.delete(); const reaction = collected.first(); + if(!reaction || !reaction.emoji || !reaction.emoji.name) return message.channel.send("could not get result"); if(reaction.emoji.name == "⬆") { + await message.reactions.removeAll(); + if(reaction.users.cache) console.log(`[twttr] tweet reply (${args[0]}) approved by ${reaction.users.cache.last().tag}: ${tweet}`); var client = new Twitter({ consumer_key: process.env.TWITTER_KEY, consumer_secret: process.env.TWITTER_SECRET, access_token_key: process.env.TWITTER_ACCESS, access_token_secret: process.env.TWITTER_ACCESS_SECRET }); - message.channel.send(`${config.misc.emoji.loading} ${vukkytils.getString("TWEETING")}`).then(tweeting => { - client.post("statuses/update", {status: args.slice(1).join(" "), in_reply_to_status_id: args[0], auto_populate_reply_metadata: true}) - .then(function (tweet) { - tweeting.delete(); - message.react("✅"); + await message.react(config.misc.emoji.loading); + let status = { + status: tweet, + in_reply_to_status_id: args[0], + auto_populate_reply_metadata: true + }; + if(attachments.length == 1) { + await fetch(attachments[0]) + .then(res => res.buffer()) + .then(buffer => { + client.post("media/upload", {media: buffer}, async function(error, media) { + if (!error) { + status.media_ids = media.media_id_string; + post(); + } else { + console.error(error); + await message.reactions.removeAll(); + await message.react("❌"); + message.reply("there was an error!", embeds.errorEmbed(`${error.message ? error.message : "Unknown error."}`)); + } + }); + }); + } else { + post(); + } + function post() { + client.post("statuses/update", status) + .then(async function (tweet) { + await message.reactions.removeAll(); + await message.react("✅"); message.reply(format(vukkytils.getString("TWEET_APPROVED"), `https://twitter.com/i/status/${tweet.id_str}`)); }) - .catch(function (error) { - tweeting.delete(); - message.react("❌"); + .catch(async function (error) { + await message.reactions.removeAll(); + await message.react("❌"); message.reply("there was an error!", embeds.errorEmbed(`${error.message ? error.message : "Unknown error."}`)); throw error; }); - }); + } } else if (reaction.emoji.name == "⬇") { - message.react("❌"); - message.reply(vukkytils.getString("TWEET_DENIED")); + if(!selfdownvote) { + await message.reactions.removeAll(); + if(reaction.users.cache) console.log(`[twttr] tweet reply (${args[0]}) denied by ${reaction.users.cache.last().tag}: ${tweet}`); + message.react("❌"); + message.reply(vukkytils.getString("TWEET_DENIED")); + } else { + message.delete(); + } } }); }); diff --git a/commands/wanted.js b/commands/wanted.js index c57c88c7..d297ebe5 100644 --- a/commands/wanted.js +++ b/commands/wanted.js @@ -1,12 +1,21 @@ const canvacord = require("canvacord").Canvas; const Discord = require("discord.js"); +const config = require("../config.json"); module.exports = { name: "wanted", description: "you are wanted! $5,000 reward!", botPermissions: ["ATTACH_FILES"], + usage: "[user]", async execute(message, args) { - const wanted = await canvacord.wanted(message.author.avatarURL({ format: "png" })); - message.channel.send(new Discord.MessageAttachment(wanted, "trash.png")); + await message.react(config.misc.emoji.loading); + let wanted; + if(message.mentions.users.size) { + wanted = await canvacord.wanted(message.mentions.users.first().avatarURL({ format: "png" })); + } else { + wanted = await canvacord.wanted(message.author.avatarURL({ format: "png" })); + } + await message.reactions.removeAll(); + message.channel.send(new Discord.MessageAttachment(wanted, "wanted.png")); }, }; diff --git a/commands/warn.js b/commands/warn.js index 677cb4c2..267ba249 100644 --- a/commands/warn.js +++ b/commands/warn.js @@ -23,7 +23,7 @@ function everythingIsFine(message, mentionedUser, args) { let sql = `INSERT INTO warnings (username, serverid, uid, reason) VALUES ('DEPRECATED', ${message.guild.id} , ${mentionedUser.id}, '${warnReason}')`; con.query(sql, function (err, result) { if (err) { - message.channel.send(errorEmbed("An error has occurred! See logs for more information.")); + message.channel.send(errorEmbed("See logs for more information.")); console.log(err); con.end(); } else { diff --git a/commands/warns.js b/commands/warns.js index 983a5397..5ae38d24 100644 --- a/commands/warns.js +++ b/commands/warns.js @@ -10,29 +10,32 @@ module.exports = { name: "warns", description: "View warnings created using VukkyBot", botPermissions: ["EMBED_LINKS", "MANAGE_MESSAGES"], - userPermissions: ["MANAGE_MESSAGES"], - args: true, mysql: true, guildOnly: true, - usage: "<@user | user id>", + usage: "<@user | user id> (if not specified, shows self)", aliases: ["warnings"], cooldown: 0, execute(message, args) { let warnsId; let mentionedUser; - if (isNaN(args[0])) { + if (isNaN(args[0]) && message.mentions.users.first()) { mentionedUser = message.guild.member(message.mentions.users.first()).user; warnsId = mentionedUser.id; everythingIsFine(); - } else { + } else if (args[0]) { warnsId = args[0]; mentionedUser = message.client.users.fetch(warnsId).then(function (res) { mentionedUser = res; everythingIsFine(); }); + } else { + mentionedUser = message.author; + warnsId = mentionedUser.id; + everythingIsFine(); } function everythingIsFine() { + if(warnsId != message.author.id && !message.member.hasPermission("MANAGE_MESSAGES")) return message.channel.send(vukkytils.getString("WARNING_CANT_SEE_OTHER")); var con = mysql.createConnection({ host: process.env.SQL_HOST, user: process.env.SQL_USER, @@ -47,7 +50,7 @@ module.exports = { let sql = `SELECT * FROM warnings WHERE (uid = ${warnsId} AND serverid = ${message.guild.id})`; con.query(sql, function (err, result) { if (err) { - message.channel.send(errorEmbed(`An error has occurred! ${err}`)); + message.channel.send(errorEmbed(err)); console.log(err); con.end(); } else { diff --git a/commands/wikipedia.js b/commands/wikipedia.js index a5f6a9b4..b68dc2db 100644 --- a/commands/wikipedia.js +++ b/commands/wikipedia.js @@ -10,6 +10,7 @@ module.exports = { name: "wikipedia", description: "Search Wikipedia using VukkyBot!", botPermissions: ["EMBED_LINKS"], + aliases: ["wiki"], execute(message, args) { message.channel.send(`${config.misc.emoji.loading} ${vukkytils.getString("GETTING_DATA")}`) .then(newMessage => { diff --git a/config.json b/config.json index 9bd78a62..7efa76a8 100644 --- a/config.json +++ b/config.json @@ -17,7 +17,31 @@ }, "moderation": { "automod": { - "allowInviteLinks": false + "allowInviteLinks": false, + "allowInviteLinksBypassRoles": ["770972367227846667"], + "autoResponses": { + "enabled": true, + "responses": { + "-installvukkybot": { + "embed": { + "title": "VukkyBot is available on GitHub!", + "description": "You can also [read the documentation](https://docs.vukkyltd.xyz) if you need help.", + "url": "https://github.com/vukkyltd/vukkybot", + "footer": "VukkyBot runs on node.js with discord.js - VukkyBot requires Node 12 or above." + } + }, + "-runescapechannel": { + "embed": { + "title": "What is #runescape?", + "description": "<#825832167556120597> is for discussion about Old School RuneScape and posts levelups of the Vukky Clan. When Vukky, Velocity, or Skelly levels up, a notification is sent there.", + "footer": "If you're using this outside of Vukky's Chat Place, you can ignore it." + } + }, + "sus": { + "text": "<:sus:826940247317151764>" + } + } + } } }, "counting": { diff --git a/index.js b/index.js index a834c22f..520c079c 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,11 @@ +// Copyright (C) 2019-2021 Vukky, Gravity Assist, Skelly + require("dotenv").config(); const fs = require("fs"); const counting = require("./counting.js"); const Discord = require("discord.js"); const ora = require("ora"); const client = new Discord.Client({partials: ["MESSAGE", "CHANNEL", "REACTION", "USER"]}); -const chalk = require("chalk"); -const success = chalk.green; -const warn = chalk.yellow; -const error = chalk.bold.red; -const info = chalk.blue; const fetch = require("node-fetch"); const pjson = require("./package.json"); const embeds = require("./utilities/embeds"); @@ -26,35 +23,72 @@ let embedPermissions = 1; console.clear(); console.log(`[${vukkytils.getString("STARTUP")}] ${vukkytils.getString("STARTING")}`); -const commandSpinner = ora(`${vukkytils.getString("STARTUP_LOADING_COMMANDS")}\n`).start(); -commandSpinner.prefixText = `[${vukkytils.getString("STARTUP")}]`; -commandSpinner.spinner = "point"; -commandSpinner.render(); -let commandsToLoad = commandFiles.length; -for (const file of commandFiles) { - commandsToLoad--; - commandSpinner.text = `${format(vukkytils.getString("STARTUP_LOADING_SPECIFIC_COMMAND"), file, commandFiles.indexOf(file), commandFiles.length)}\n`; - try { - commandSpinner.render(); - const command = require(`./commands/${file}`); - client.commands.set(command.name, command); - if (!command.name) { - commandSpinner.fail(`Couldn't load ${file}: No name`); - process.exit(1); - } else if (!command.execute) { - commandSpinner.fail(`Couldn't load ${file}: No execute function`); - process.exit(1); +async function checkUpdates(forStartup) { + const updateChecker = ora("Checking for updates...").start(); + updateChecker.prefixText = forStartup == true ? `[${vukkytils.getString("STARTUP")}]` : "[updater]"; + updateChecker.spinner = "point"; + updateChecker.render(); + fetch("https://raw.githubusercontent.com/VukkyLtd/VukkyBot/master/package.json") + .then(res => res.json()) + .then(json => { + if (json.version > pjson.version && updateRemindedOn !== json.version) { + updateChecker.warn(`${json.version} is now available!`); + console.log(`[updater] https://github.com/VukkyLtd/VukkyBot/releases/tag/${json.version}`); + updateRemindedOn = json.version; + if (config.updateChecker.dmOwner) { + for (let i = 0; i < config.misc.owner.length; i++) { + client.users.fetch(config.misc.owner[i].toString()) + .then(owner => { + owner.send(`Hello! I'm out of date. You're using VukkyBot **${pjson.version}**, but the latest version is VukkyBot **${json.version}**.\nhttps://github.com/VukkyLtd/VukkyBot/releases/tag/${json.version}\n*You have gotten this DM because you are an owner of this VukkyBot. DMing my owner(s) when an update is available is turned on.*`); + }); + } + } + return true; + } else { + updateChecker.info("No new updates available."); + if(forStartup == true) commandPrep(true); + return false; + } + }); +} + +function commandPrep(forStartup) { + const commandSpinner = ora(`${vukkytils.getString("STARTUP_LOADING_COMMANDS")}\n`).start(); + commandSpinner.prefixText = `[${vukkytils.getString("STARTUP")}]`; + commandSpinner.spinner = "point"; + commandSpinner.render(); + let commandsLoaded = 0; + for (const file of commandFiles) { + commandSpinner.text = `${format(vukkytils.getString("STARTUP_LOADING_SPECIFIC_COMMAND"), file, commandFiles.indexOf(file), commandFiles.length)}\n`; + try { + commandSpinner.render(); + const command = require(`./commands/${file}`); + client.commands.set(command.name, command); + if (!command.name) { + commandSpinner.fail(`Couldn't load ${file}: No name`); + process.exit(1); + } else if (!command.execute) { + commandSpinner.fail(`Couldn't load ${file}: No execute function`); + process.exit(1); + } + } catch (error) { + commandSpinner.fail(`Couldn't load ${file}: ${error.message}`); + throw error; + } + commandsLoaded++; + if(commandsLoaded == commandFiles.length) { + commandSpinner.succeed(vukkytils.getString("STARTUP_COMMANDS_LOADED")); + if(forStartup == true) login(); } - } catch (error) { - commandSpinner.fail(`Couldn't load ${file}: ${error.message}`); - throw error; - } - if(commandsToLoad == 0) { - commandSpinner.succeed(vukkytils.getString("STARTUP_COMMANDS_LOADED")); - login(); } } +if(config.updateChecker.enabled) { + checkUpdates(true); +} else { + commandPrep(true); +} + const cooldowns = new Discord.Collection(); client.once("ready", async () => { @@ -62,50 +96,40 @@ client.once("ready", async () => { if(!process.env.BOT_PREFIX && process.env.PREFIX) console.log(`[${vukkytils.getString("STARTUP")}] ${vukkytils.getString("ENV_PREFIX_RENAMED")}`); const statuses = [ "with JavaScript", - "with a Fall Guy", + "with a Vukky", "with counting bots", "with banning people", "with the console", - "with pm2", "with npm", "with ESLint", "with MySQL", "with SPAGHETTI", - "with Vukkies", + "with the Vukkies", "with node-fetch", "with vukkyutils", "with discord.js", "Fall Guys", "Among Us", - "Startup Panic", "Fortnite", - "Cyberpunk 2077", - "Cyberdelay 2077", - "Portal 3", - "GTA 6", - "GTA 7", - "Roblox 2", - "Minecraft 2", "Roblox", "Minecraft", "osu!", - "osu! 2", "Pixel Strike 3D", "Among Guys", "DropBlox", - "with the cats", "Club Penguin", - "you", "Baba is You", - "Among Them", "Vukkyland", - "Super Vukky 64", - "Paper Vukky: The Origami King", - "Swift Playgrounds", "Elemental on Discord", "Genshin Impact", "VALORANT", - "Terraria" + "Terraria", + "The Game (i lost)", + "RuneLite", + "RuneScape", + "Old School Runescape", + "on Funorb", + ]; client.user.setActivity(`with the world (${pjson.version})`); setInterval(() => { @@ -114,7 +138,6 @@ client.once("ready", async () => { }, 15000); counting.start(client); if (config.updateChecker.enabled) { - checkUpdates(); setInterval(() => { checkUpdates(); }, 7200000); @@ -148,46 +171,42 @@ client.once("ready", async () => { } } }); + embeds.setAvatarURL(client.user.displayAvatarURL()); }); -function checkUpdates() { - const updateChecker = ora("Checking for updates...").start(); - updateChecker.prefixText = "[updater]"; - updateChecker.spinner = "point"; - updateChecker.render(); - fetch("https://raw.githubusercontent.com/VukkyLtd/VukkyBot/master/package.json") - .then(res => res.json()) - .then(json => { - if (json.version > pjson.version && updateRemindedOn !== json.version) { - updateChecker.warn(`${json.version} is now available!`); - console.log(`[updater] https://github.com/VukkyLtd/VukkyBot/releases/tag/${json.version}`); - updateRemindedOn = json.version; - if (config.updateChecker.dmOwner) { - for (let i = 0; i < config.misc.owner.length; i++) { - client.users.fetch(config.misc.owner[i].toString()) - .then(owner => { - owner.send(`Hello! I'm out of date. You're using VukkyBot **${pjson.version}**, but the latest version is VukkyBot **${json.version}**.\nhttps://github.com/VukkyLtd/VukkyBot/releases/tag/${json.version}\n*You have gotten this DM because you are an owner of this VukkyBot. DMing my owner(s) when an update is available is turned on.*`); - }); - } - } - } else { - updateChecker.info("No new updates available."); - } - }); -} - -const inviteSites = ["discord.gg/", "discord.com/invite/", "discordapp.com/invite/", "discord.co/invite", "watchanimeattheoffice.com/invite/", "discord.media/invite/"]; -client.on("message", message => { +const inviteSites = ["discord.gg/", "discord.com/invite/", "discordapp.com/invite/", "discord.co/invite/", "watchanimeattheoffice.com/invite/", "discord.media/invite/"]; +client.on("message", async message => { if (message.author.bot) return; if ((message.channel.type == "text" && !message.guild.me.hasPermission("EMBED_LINKS"))) embedPermissions = 0; - if (message.content.toLowerCase().includes(`<@!${client.user.id}>`) && config.misc.prefixReminder == true && !message.content.startsWith(prefix)) message.reply(`my prefix is \`${process.env.BOT_PREFIX}\``); + if (message.content.toLowerCase().includes(`<@!${client.user.id}>`) && config.misc.prefixReminder == true && !message.content.startsWith(prefix)) message.channel.send(`Hi ${message.author}! Do you need help? Just type \`${process.env.BOT_PREFIX}help\`, and I'll send you all my commands!\nYou have to put \`${process.env.BOT_PREFIX}\` before the name of a command in order to make it work.`); if (message.channel.name == config.counting.channelName) counting.check(message, client); - if (inviteSites.some(site => message.content.includes(site)) && config.moderation.automod.allowInviteLinks == false) { + if (inviteSites.some(site => message.content.includes(site)) && config.moderation.automod.allowInviteLinks == false && !message.member.roles.cache.some(r => config.moderation.automod.allowInviteLinksBypassRoles.includes(r.id))) { message.delete(); message.channel.send(format(vukkytils.getString("DISCORD_INVITES_DISABLED_AUTOMOD"), message.author)).then(msg => setTimeout(() => msg.delete(), 7000)); } + // Send auto responses configured in config.moderation.automod.autoResponses + if(config.moderation.automod.autoResponses.enabled && config.moderation.automod.autoResponses.responses[message.content.toLowerCase()]) { + let autoResponse = config.moderation.automod.autoResponses.responses[message.content.toLowerCase()]; + if(autoResponse.text && !autoResponse.embed) { + message.channel.send(autoResponse.text); + } else if (autoResponse.embed && Object.keys(autoResponse.embed).length > 0) { + let embed = new Discord.MessageEmbed(); + if(autoResponse.embed.title) embed.setTitle(autoResponse.embed.title); + if(autoResponse.embed.description) embed.setDescription(autoResponse.embed.description); + if(autoResponse.embed.url) embed.setURL(autoResponse.embed.url); + if(autoResponse.embed.footer) embed.setFooter(autoResponse.embed.footer); + if(autoResponse.text) { + message.channel.send(autoResponse.text, embed); + } else { + message.channel.send(embed); + } + } else { + message.channel.send("There's something wrong with this auto response! Contact the server administrator."); + } + } + if (!message.content.toLowerCase().startsWith(prefix)) return; const args = message.content.slice(prefix.length).split(/ +/); @@ -198,6 +217,7 @@ client.on("message", message => { const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); + // Make sure the command exists if (!command) { if(config.misc.invalidCmdReminder) { let reply = `I've been looking around for a while now, but I don't think **${commandName}** is a command.`; @@ -207,6 +227,7 @@ client.on("message", message => { return; } + // Handle various exports if(command.mysql && !config.misc.mysql) { if (embedPermissions == 0) return message.channel.send(`**${commandName}** is not enabled on this VukkyBot because MySQL is disabled!\nFor the hoster: See https://vukkyltd.github.io/VukkyBot/troubleshooting/mysqldisabled.html for instructions on how to enable it!`); return message.channel.send(embeds.errorEmbed(`**${commandName}** is not enabled on this VukkyBot because MySQL is disabled!\nFor the hoster: See [the VukkyBot Documentation site](https://vukkyltd.github.io/VukkyBot/troubleshooting/mysqldisabled.html) for instructions on how to enable it!`)); @@ -222,7 +243,7 @@ client.on("message", message => { return message.channel.send(embeds.errorEmbed(`**${commandName}** requires you to be the owner of this VukkyBot to use it.`)); } - if (command.guildOnly && message.channel.type !== "text") { + if (command.guildOnly && message.channel.type == "dm") { return message.channel.send(embeds.errorEmbed(`**${commandName}** cannot be used inside DMs.`)); } @@ -270,11 +291,12 @@ client.on("message", message => { const timestamps = cooldowns.get(command.name); const cooldownAmount = (command.cooldown || 3) * 1000; - if (timestamps.has(message.author.id)) { + if (timestamps.has(message.author.id) && !config.misc.owner.includes(message.author.id)) { const expirationTime = timestamps.get(message.author.id) + cooldownAmount; if (now < expirationTime) { const timeLeft = (expirationTime - now) / 1000; + console.log(timeLeft.toFixed(0)); return message.channel.send(embeds.cooldownEmbed(`You need to wait ${timeLeft.toFixed(1)} more second(s) before you can use the \`${command.name}\` command again.`)); } } @@ -282,22 +304,24 @@ client.on("message", message => { timestamps.set(message.author.id, now); setTimeout(() => timestamps.delete(message.author.id), cooldownAmount); + // Execute the command try { command.execute(message, args); } catch (error) { console.log(`[${command.name}] ${error.message}`); + console.error(error); message.reply("there was an error trying to execute that command!", embeds.errorEmbed(error.message)); } }); client.on("messageUpdate", async (oldMessage, newMessage) => { - if (newMessage.partial) { + if (newMessage && newMessage.partial) { await newMessage.fetch() .catch(error => { console.log("Something went wrong when fetching the message: ", error); }); } - if (newMessage && newMessage.content && inviteSites.some(site => newMessage.content.includes(site)) && config.moderation.automod.allowInviteLinks == false) { + if (newMessage && newMessage.content && inviteSites.some(site => newMessage.content.includes(site)) && config.moderation.automod.allowInviteLinks == false && !newMessage.member.roles.cache.some(r => config.moderation.automod.allowInviteLinksBypassRoles.includes(r))) { newMessage.delete(); newMessage.channel.send(format(vukkytils.getString("DISCORD_INVITES_DISABLED_AUTOMOD"), newMessage.author)).then(msg => setTimeout(() => msg.delete(), 7000)); } @@ -337,7 +361,7 @@ client.on("messageReactionAdd", async function(reaction, user){ reportMessage.edit(embeds.reportActionEmbed("The reported message was deleted.", reaction.message.content, actionReaction.users.cache.last())); } }) - .catch(collected => { + .catch(() => { return reportMessage.channel.send("There was an error."); }); }); @@ -361,3 +385,7 @@ async function login() { throw e; } } + +process.on("uncaughtException", function (err) { + console.error(err); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ebd754b7..8f774729 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,17 +14,17 @@ "chalk": "^4.1.0", "chokidar": "^3.5.1", "comma-number": "^2.0.1", - "discord.js": "^12.5.1", + "discord.js": "^12.5.2", "dotenv": "^8.2.0", "minecraft-server-util": "^3.4.4", "mysql": "^2.18.1", - "ora": "^5.3.0", + "ora": "^5.4.0", "twitter": "^1.7.1" }, "devDependencies": { "eslint": "^7.22.0", "inquirer": "^8.0.0", - "npm": "^7.6.3" + "npm": "^7.8.0" } }, "node_modules/@babel/code-frame": { @@ -375,7 +375,21 @@ "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -407,9 +421,9 @@ } }, "node_modules/bl": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", - "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -429,19 +443,6 @@ "node": ">= 6" } }, - "node_modules/bl/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "node_modules/bl/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -466,6 +467,20 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -751,18 +766,18 @@ } }, "node_modules/discord.js": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.1.tgz", - "integrity": "sha512-VwZkVaUAIOB9mKdca0I5MefPMTQJTNg0qdgi1huF3iwsFwJ0L5s/Y69AQe+iPmjuV6j9rtKoG0Ta0n9vgEIL6w==", + "version": "12.5.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.2.tgz", + "integrity": "sha512-PAJv2azCHZNz5VlSOcEYS3SPBmYvka0WHlWhTlHgorfJVRcm1xPwYFqPeU+8+YsWlUxkfgGUD2bnNkVx6vIqPw==", "dependencies": { "@discordjs/collection": "^0.1.6", "@discordjs/form-data": "^3.0.1", "abort-controller": "^3.0.0", "node-fetch": "^2.6.1", - "prism-media": "^1.2.2", + "prism-media": "^1.2.9", "setimmediate": "^1.0.5", "tweetnacl": "^1.0.3", - "ws": "^7.3.1" + "ws": "^7.4.4" }, "engines": { "node": ">=12.0.0" @@ -1415,7 +1430,21 @@ "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/ignore": { "version": "4.0.6", @@ -1562,6 +1591,17 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1639,14 +1679,18 @@ "dev": true }, "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dependencies": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mime-db": { @@ -1894,9 +1938,9 @@ } }, "node_modules/npm": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/npm/-/npm-7.6.3.tgz", - "integrity": "sha512-+Cs8TEtkfdQGTIPw8AeqVtNNHyo1Zw8HATzAFFWYnK7jQYgT/CatEy85+BlEoEpqvga2uaKqVrXsTAYj28emjg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-7.8.0.tgz", + "integrity": "sha512-9AC3Dj9OUWaUdmTmEVttE/1MWkfF7+sAKPRo9tKEyjo49AXmHQBn+RC33M9dima91mEMqDIA71xyRm4VmhDipg==", "bundleDependencies": [ "@npmcli/arborist", "@npmcli/ci-detect", @@ -2099,7 +2143,6 @@ "promise-retry", "promzard", "psl", - "puka", "punycode", "qs", "read-cmd-shim", @@ -2142,16 +2185,16 @@ ], "dev": true, "dependencies": { - "@npmcli/arborist": "^2.2.8", + "@npmcli/arborist": "^2.3.0", "@npmcli/ci-detect": "^1.2.0", - "@npmcli/config": "^1.2.9", - "@npmcli/run-script": "^1.8.3", + "@npmcli/config": "^2.1.0", + "@npmcli/run-script": "^1.8.4", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", "archy": "~1.0.0", "byte-size": "^7.0.1", - "cacache": "^15.0.5", + "cacache": "^15.0.6", "chalk": "^4.1.0", "chownr": "^2.0.0", "cli-columns": "^3.1.2", @@ -2159,7 +2202,7 @@ "columnify": "~1.5.4", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "hosted-git-info": "^3.0.8", + "hosted-git-info": "^4.0.2", "ini": "^2.0.0", "init-package-json": "^2.0.2", "is-cidr": "^4.0.2", @@ -2174,7 +2217,7 @@ "libnpmpublish": "^4.0.0", "libnpmsearch": "^3.1.0", "libnpmteam": "^2.0.2", - "libnpmversion": "^1.0.11", + "libnpmversion": "^1.1.0", "make-fetch-happen": "^8.0.14", "minipass": "^3.1.3", "minipass-pipeline": "^1.2.4", @@ -2184,14 +2227,14 @@ "node-gyp": "^7.1.2", "nopt": "^5.0.0", "npm-audit-report": "^2.1.4", - "npm-package-arg": "^8.1.1", - "npm-pick-manifest": "^6.1.0", + "npm-package-arg": "^8.1.2", + "npm-pick-manifest": "^6.1.1", "npm-profile": "^5.0.2", "npm-registry-fetch": "^9.0.0", "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.3.0", + "pacote": "^11.3.1", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", @@ -2199,7 +2242,7 @@ "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", "rimraf": "^3.0.2", - "semver": "^7.3.4", + "semver": "^7.3.5", "ssri": "^8.0.1", "tar": "^6.1.0", "text-table": "~0.2.0", @@ -2241,7 +2284,7 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "2.2.8", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "ISC", @@ -2257,7 +2300,7 @@ "cacache": "^15.0.3", "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.1", + "json-stringify-nice": "^1.1.2", "mkdirp-infer-owner": "^2.0.0", "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", @@ -2269,7 +2312,7 @@ "promise-call-limit": "^1.0.1", "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", - "semver": "^7.3.4", + "semver": "^7.3.5", "tar": "^6.1.0", "treeverse": "^1.0.4", "walk-up-path": "^1.0.0" @@ -2285,7 +2328,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "1.2.9", + "version": "2.1.0", "dev": true, "inBundle": true, "license": "ISC", @@ -2361,7 +2404,7 @@ } }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "1.1.0", + "version": "1.1.1", "dev": true, "inBundle": true, "license": "ISC", @@ -2406,7 +2449,7 @@ } }, "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "1.8.3", + "version": "1.8.4", "dev": true, "inBundle": true, "license": "ISC", @@ -2415,7 +2458,6 @@ "@npmcli/promise-spawn": "^1.3.2", "infer-owner": "^1.0.4", "node-gyp": "^7.1.0", - "puka": "^1.0.1", "read-package-json-fast": "^2.0.1" } }, @@ -2659,7 +2701,7 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "15.0.5", + "version": "15.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -2678,7 +2720,7 @@ "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", - "ssri": "^8.0.0", + "ssri": "^8.0.1", "tar": "^6.0.2", "unique-filename": "^1.1.1" }, @@ -2786,7 +2828,7 @@ } }, "node_modules/npm/node_modules/cli-table3/node_modules/string-width": { - "version": "4.2.0", + "version": "4.2.2", "dev": true, "inBundle": true, "license": "MIT", @@ -3038,7 +3080,7 @@ } }, "node_modules/npm/node_modules/env-paths": { - "version": "2.2.0", + "version": "2.2.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3259,7 +3301,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/hosted-git-info": { - "version": "3.0.8", + "version": "4.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -3519,7 +3561,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.1", + "version": "1.1.3", "dev": true, "inBundle": true, "license": "ISC", @@ -3703,14 +3745,14 @@ } }, "node_modules/npm/node_modules/libnpmversion": { - "version": "1.0.11", + "version": "1.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/git": "^2.0.6", "@npmcli/run-script": "^1.8.3", - "read-package-json-fast": "^2.0.1", + "json-parse-even-better-errors": "^2.3.1", "semver": "^7.3.4", "stringify-package": "^1.0.1" } @@ -3754,7 +3796,7 @@ } }, "node_modules/npm/node_modules/mime-db": { - "version": "1.45.0", + "version": "1.46.0", "dev": true, "inBundle": true, "license": "MIT", @@ -3763,12 +3805,12 @@ } }, "node_modules/npm/node_modules/mime-types": { - "version": "2.1.28", + "version": "2.1.29", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "mime-db": "1.45.0" + "mime-db": "1.46.0" }, "engines": { "node": ">= 0.6" @@ -3964,14 +4006,14 @@ } }, "node_modules/npm/node_modules/normalize-package-data": { - "version": "3.0.0", + "version": "3.0.2", "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { - "hosted-git-info": "^3.0.6", - "resolve": "^1.17.0", - "semver": "^7.3.2", + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" }, "engines": { @@ -4018,13 +4060,13 @@ "license": "ISC" }, "node_modules/npm/node_modules/npm-package-arg": { - "version": "8.1.1", + "version": "8.1.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "hosted-git-info": "^3.0.6", - "semver": "^7.0.0", + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", "validate-npm-package-name": "^3.0.0" }, "engines": { @@ -4032,7 +4074,7 @@ } }, "node_modules/npm/node_modules/npm-packlist": { - "version": "2.1.4", + "version": "2.1.5", "dev": true, "inBundle": true, "license": "ISC", @@ -4050,14 +4092,15 @@ } }, "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "6.1.0", + "version": "6.1.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.0.0", - "semver": "^7.0.0" + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" } }, "node_modules/npm/node_modules/npm-profile": { @@ -4170,7 +4213,7 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "11.3.0", + "version": "11.3.1", "dev": true, "inBundle": true, "license": "ISC", @@ -4292,15 +4335,6 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/puka": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/npm/node_modules/punycode": { "version": "2.1.1", "dev": true, @@ -4494,7 +4528,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/semver": { - "version": "7.3.4", + "version": "7.3.5", "dev": true, "inBundle": true, "license": "ISC", @@ -4531,7 +4565,7 @@ } }, "node_modules/npm/node_modules/socks": { - "version": "2.5.1", + "version": "2.6.0", "dev": true, "inBundle": true, "license": "MIT", @@ -4950,21 +4984,25 @@ } }, "node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz", + "integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==", "dependencies": { - "bl": "^4.0.3", + "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/os-homedir": { @@ -5038,9 +5076,29 @@ } }, "node_modules/prism-media": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.2.tgz", - "integrity": "sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw==" + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.9.tgz", + "integrity": "sha512-UHCYuqHipbTR1ZsXr5eg4JUmHER8Ss4YEb9Azn+9zzJ7/jlTtD1h0lc4g6tNx3eMlB8Mp6bfll0LPMAV4R6r3Q==", + "peerDependencies": { + "@discordjs/opus": "^0.5.0", + "ffmpeg-static": "^4.2.7 || ^3.0.0 || ^2.4.0", + "node-opus": "^0.3.3", + "opusscript": "^0.0.8" + }, + "peerDependenciesMeta": { + "@discordjs/opus": { + "optional": true + }, + "ffmpeg-static": { + "optional": true + }, + "node-opus": { + "optional": true + }, + "opusscript": { + "optional": true + } + } }, "node_modules/process-nextick-args": { "version": "2.0.1", @@ -5390,6 +5448,33 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -5687,11 +5772,23 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/ws": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", - "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", "engines": { "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/yallist": { @@ -6019,9 +6116,9 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bl": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", - "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -6037,19 +6134,6 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } } } }, @@ -6289,18 +6373,18 @@ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, "discord.js": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.1.tgz", - "integrity": "sha512-VwZkVaUAIOB9mKdca0I5MefPMTQJTNg0qdgi1huF3iwsFwJ0L5s/Y69AQe+iPmjuV6j9rtKoG0Ta0n9vgEIL6w==", + "version": "12.5.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.2.tgz", + "integrity": "sha512-PAJv2azCHZNz5VlSOcEYS3SPBmYvka0WHlWhTlHgorfJVRcm1xPwYFqPeU+8+YsWlUxkfgGUD2bnNkVx6vIqPw==", "requires": { "@discordjs/collection": "^0.1.6", "@discordjs/form-data": "^3.0.1", "abort-controller": "^3.0.0", "node-fetch": "^2.6.1", - "prism-media": "^1.2.2", + "prism-media": "^1.2.9", "setimmediate": "^1.0.5", "tweetnacl": "^1.0.3", - "ws": "^7.3.1" + "ws": "^7.4.4" } }, "doctrine": { @@ -6922,6 +7006,11 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -6993,11 +7082,12 @@ "dev": true }, "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "requires": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" } }, "mime-db": { @@ -7191,21 +7281,21 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "npm": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/npm/-/npm-7.6.3.tgz", - "integrity": "sha512-+Cs8TEtkfdQGTIPw8AeqVtNNHyo1Zw8HATzAFFWYnK7jQYgT/CatEy85+BlEoEpqvga2uaKqVrXsTAYj28emjg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-7.8.0.tgz", + "integrity": "sha512-9AC3Dj9OUWaUdmTmEVttE/1MWkfF7+sAKPRo9tKEyjo49AXmHQBn+RC33M9dima91mEMqDIA71xyRm4VmhDipg==", "dev": true, "requires": { - "@npmcli/arborist": "^2.2.8", + "@npmcli/arborist": "^2.3.0", "@npmcli/ci-detect": "^1.2.0", - "@npmcli/config": "^1.2.9", - "@npmcli/run-script": "^1.8.3", + "@npmcli/config": "^2.1.0", + "@npmcli/run-script": "^1.8.4", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", "archy": "~1.0.0", "byte-size": "^7.0.1", - "cacache": "^15.0.5", + "cacache": "^15.0.6", "chalk": "^4.1.0", "chownr": "^2.0.0", "cli-columns": "^3.1.2", @@ -7213,7 +7303,7 @@ "columnify": "~1.5.4", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "hosted-git-info": "^3.0.8", + "hosted-git-info": "^4.0.2", "ini": "^2.0.0", "init-package-json": "^2.0.2", "is-cidr": "^4.0.2", @@ -7228,7 +7318,7 @@ "libnpmpublish": "^4.0.0", "libnpmsearch": "^3.1.0", "libnpmteam": "^2.0.2", - "libnpmversion": "^1.0.11", + "libnpmversion": "^1.1.0", "make-fetch-happen": "^8.0.14", "minipass": "^3.1.3", "minipass-pipeline": "^1.2.4", @@ -7238,14 +7328,14 @@ "node-gyp": "^7.1.2", "nopt": "^5.0.0", "npm-audit-report": "^2.1.4", - "npm-package-arg": "^8.1.1", - "npm-pick-manifest": "^6.1.0", + "npm-package-arg": "^8.1.2", + "npm-pick-manifest": "^6.1.1", "npm-profile": "^5.0.2", "npm-registry-fetch": "^9.0.0", "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.3.0", + "pacote": "^11.3.1", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", @@ -7253,7 +7343,7 @@ "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", "rimraf": "^3.0.2", - "semver": "^7.3.4", + "semver": "^7.3.5", "ssri": "^8.0.1", "tar": "^6.1.0", "text-table": "~0.2.0", @@ -7265,7 +7355,7 @@ }, "dependencies": { "@npmcli/arborist": { - "version": "2.2.8", + "version": "2.3.0", "bundled": true, "dev": true, "requires": { @@ -7280,7 +7370,7 @@ "cacache": "^15.0.3", "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.1", + "json-stringify-nice": "^1.1.2", "mkdirp-infer-owner": "^2.0.0", "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", @@ -7292,7 +7382,7 @@ "promise-call-limit": "^1.0.1", "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", - "semver": "^7.3.4", + "semver": "^7.3.5", "tar": "^6.1.0", "treeverse": "^1.0.4", "walk-up-path": "^1.0.0" @@ -7304,7 +7394,7 @@ "dev": true }, "@npmcli/config": { - "version": "1.2.9", + "version": "2.1.0", "bundled": true, "dev": true, "requires": { @@ -7360,7 +7450,7 @@ } }, "@npmcli/metavuln-calculator": { - "version": "1.1.0", + "version": "1.1.1", "bundled": true, "dev": true, "requires": { @@ -7397,7 +7487,7 @@ } }, "@npmcli/run-script": { - "version": "1.8.3", + "version": "1.8.4", "bundled": true, "dev": true, "requires": { @@ -7405,7 +7495,6 @@ "@npmcli/promise-spawn": "^1.3.2", "infer-owner": "^1.0.4", "node-gyp": "^7.1.0", - "puka": "^1.0.1", "read-package-json-fast": "^2.0.1" } }, @@ -7583,7 +7672,7 @@ "dev": true }, "cacache": { - "version": "15.0.5", + "version": "15.0.6", "bundled": true, "dev": true, "requires": { @@ -7601,7 +7690,7 @@ "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", - "ssri": "^8.0.0", + "ssri": "^8.0.1", "tar": "^6.0.2", "unique-filename": "^1.1.1" } @@ -7668,7 +7757,7 @@ "dev": true }, "string-width": { - "version": "4.2.0", + "version": "4.2.2", "bundled": true, "dev": true, "requires": { @@ -7850,7 +7939,7 @@ } }, "env-paths": { - "version": "2.2.0", + "version": "2.2.1", "bundled": true, "dev": true }, @@ -8011,7 +8100,7 @@ "dev": true }, "hosted-git-info": { - "version": "3.0.8", + "version": "4.0.2", "bundled": true, "dev": true, "requires": { @@ -8203,7 +8292,7 @@ "dev": true }, "json-stringify-nice": { - "version": "1.1.1", + "version": "1.1.3", "bundled": true, "dev": true }, @@ -8335,13 +8424,13 @@ } }, "libnpmversion": { - "version": "1.0.11", + "version": "1.1.0", "bundled": true, "dev": true, "requires": { "@npmcli/git": "^2.0.6", "@npmcli/run-script": "^1.8.3", - "read-package-json-fast": "^2.0.1", + "json-parse-even-better-errors": "^2.3.1", "semver": "^7.3.4", "stringify-package": "^1.0.1" } @@ -8377,16 +8466,16 @@ } }, "mime-db": { - "version": "1.45.0", + "version": "1.46.0", "bundled": true, "dev": true }, "mime-types": { - "version": "2.1.28", + "version": "2.1.29", "bundled": true, "dev": true, "requires": { - "mime-db": "1.45.0" + "mime-db": "1.46.0" } }, "minimatch": { @@ -8517,13 +8606,13 @@ } }, "normalize-package-data": { - "version": "3.0.0", + "version": "3.0.2", "bundled": true, "dev": true, "requires": { - "hosted-git-info": "^3.0.6", - "resolve": "^1.17.0", - "semver": "^7.3.2", + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, @@ -8557,17 +8646,17 @@ "dev": true }, "npm-package-arg": { - "version": "8.1.1", + "version": "8.1.2", "bundled": true, "dev": true, "requires": { - "hosted-git-info": "^3.0.6", - "semver": "^7.0.0", + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", "validate-npm-package-name": "^3.0.0" } }, "npm-packlist": { - "version": "2.1.4", + "version": "2.1.5", "bundled": true, "dev": true, "requires": { @@ -8578,13 +8667,14 @@ } }, "npm-pick-manifest": { - "version": "6.1.0", + "version": "6.1.1", "bundled": true, "dev": true, "requires": { "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.0.0", - "semver": "^7.0.0" + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" } }, "npm-profile": { @@ -8663,7 +8753,7 @@ } }, "pacote": { - "version": "11.3.0", + "version": "11.3.1", "bundled": true, "dev": true, "requires": { @@ -8755,11 +8845,6 @@ "bundled": true, "dev": true }, - "puka": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, "punycode": { "version": "2.1.1", "bundled": true, @@ -8904,7 +8989,7 @@ "dev": true }, "semver": { - "version": "7.3.4", + "version": "7.3.5", "bundled": true, "dev": true, "requires": { @@ -8927,7 +9012,7 @@ "dev": true }, "socks": { - "version": "2.5.1", + "version": "2.6.0", "bundled": true, "dev": true, "requires": { @@ -9278,16 +9363,17 @@ } }, "ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz", + "integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==", "requires": { - "bl": "^4.0.3", + "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } @@ -9342,9 +9428,10 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "prism-media": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.2.tgz", - "integrity": "sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw==" + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.9.tgz", + "integrity": "sha512-UHCYuqHipbTR1ZsXr5eg4JUmHER8Ss4YEb9Azn+9zzJ7/jlTtD1h0lc4g6tNx3eMlB8Mp6bfll0LPMAV4R6r3Q==", + "requires": {} }, "process-nextick-args": { "version": "2.0.1", @@ -9615,6 +9702,21 @@ } } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -9851,9 +9953,10 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", - "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "requires": {} }, "yallist": { "version": "3.1.1", diff --git a/package.json b/package.json index b6d2edb2..2c7a9fd5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vukkybot", "version": "3.0.0", - "date": "27/03/2021", + "date": "07/04/2021", "dateFormat": "DD/MM/YYYY", "description": "VukkyBot", "main": "index.js", @@ -11,17 +11,17 @@ "chalk": "^4.1.0", "chokidar": "^3.5.1", "comma-number": "^2.0.1", - "discord.js": "^12.5.1", + "discord.js": "^12.5.2", "dotenv": "^8.2.0", "minecraft-server-util": "^3.4.4", "mysql": "^2.18.1", - "ora": "^5.3.0", + "ora": "^5.4.0", "twitter": "^1.7.1" }, "devDependencies": { "eslint": "^7.22.0", "inquirer": "^8.0.0", - "npm": "^7.6.3" + "npm": "^7.8.0" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/strings/en.json b/strings/en.json index 04e2c7ff..7780a85d 100644 --- a/strings/en.json +++ b/strings/en.json @@ -11,8 +11,8 @@ "HEADPAT_TYPES": ["an okay headpat.", "a great headpat.", "an AMAZING headpat!"], "SLAP_TYPES": "a big slap in the face!", "GIVE_USER": "%s gives %s %s", - "WARNINGS_TITLE": "Warnings for %s", - "NO_WARNINGS": "This person has no warnings.", + "WARNINGS_TITLE": "%s's warnings", + "NO_WARNINGS": "This person doesn't have any warnings! ✨", "BOT_LOVE": "Aww, thanks! ♥", "BOT_PAIN": "Why did you even try? :(", "CANT_HUG_SELF": "You can't hug yourself! That would be silly.", @@ -21,12 +21,11 @@ "CANT_KICK_SELF": "You can't kick yourself! That would be silly.", "CANT_BAN_SELF": "You can't ban yourself! That would be silly.", "PING_REQUIRED": "You need to ping someone to use this command.", - "TWEETING": "Tweeting...", "TWEET_APPROVED": "your tweet was approved by a user! Here it is: %s", "TWEET_DENIED": "your tweet was denied by a user.", "TWEET_REPLYING_TO": "you are replying to %s", - "WARNING_ADDED": "Warning added to %s, for %s.", - "GOT_WARNED": "⚠ You were warned in **%s**, for %s.", + "WARNING_ADDED": "%s now has a warning for %s.", + "GOT_WARNED": "⚠ Hi! You got warned in **%s** for %s.", "DISCOVERING_OTHER_VUKKY": "Hold on! I'm discovering **%s**'s inner Vukky!", "DISCOVERING_VUKKY": "Hold on! I'm discovering your inner Vukky!", "DISCOVERED_OTHER_VUKKY": "%s, here is **%s**'s inner Vukky!", @@ -42,7 +41,7 @@ "COVID_ACTIVE": "Active", "COVID_CRITICAL": "Critical", "COVID_TESTS": "Tests", - "API_CREDIT": "Thank you to <%s>!", + "API_CREDIT": "🌐 This response is powered by the nice people at <%s>.", "DUCK_FINDING": "Hold on! I'm finding a duck for you... 🦆🦆🦆", "ENV_PREFIX_RENAMED": "PREFIX is now BOT_PREFIX. Please change your .env file.", "WARNING": "Warning", @@ -73,7 +72,7 @@ "TIH_LINKS": "Links", "DEBUG": "debug", "DEBUG_DEV_MODE": "Developer mode is enabled.", - "GETTING_DATA": "Hold on! I'm getting the data...", + "GETTING_DATA": "Connecting to an external server...", "WIKIPEDIA_DOESNT_EXIST": "`%s` doesn't exist.", "WIKIPEDIA_INVALID_CHARS": "`%s` contains invalid characters.", "WIKIPEDIA_NO_SHORT_DESC": "No short description availabile", @@ -106,5 +105,7 @@ "STARTUP_LOGIN_FAILED_INTERNET_UNAVAILABLE": "Login failed - your internet connection may be unavailable.", "DISCORD_INVITES_DISABLED_AUTOMOD": "%s, **sending Discord invites** is disabled in this server.", "INNER_VUKKY_ERROR": "The Vukky seems to be hiding...", - "INNER_VUKKY_USER_FETCH_ERROR": "The Vukky seems to be hiding... Are you sure that's a real person?" + "INNER_VUKKY_USER_FETCH_ERROR": "The Vukky seems to be hiding... Are you sure that's a real person?", + "WARNING_CANT_SEE_OTHER": "Sorry, but you need the `MANAGE_MESSAGES` permission to see other people's warnings.", + "HELP_NO_DESCRIPTION": "It looks like this command doesn't have any description." } \ No newline at end of file diff --git a/utilities/embeds.js b/utilities/embeds.js index c4dea3cd..34736026 100644 --- a/utilities/embeds.js +++ b/utilities/embeds.js @@ -3,13 +3,16 @@ const Discord = require("discord.js"); const pjson = require("../package.json"); const config = require("../config.json"); -const avatarURL = "https://i.imgur.com/H0sAkrl.png"; +let avatarURL = "https://i.imgur.com/H0sAkrl.png"; let versionString = `v${pjson.version} (discord.js ${pjson.dependencies["discord.js"].substring(1)})`; const vukkytils = require("./vukkytils"); const format = require("util").format; module.exports = { + versionString, + getAvatarURL, + setAvatarURL, errorEmbed, warningEmbed, infoEmbed, @@ -32,10 +35,17 @@ module.exports = { innerEmbed, reportEmbed, reportActionEmbed, - versionString, - avatarURL + tweetBlacklistEmbed, + wikipediaEmbed }; +function setAvatarURL(url) { + avatarURL = url; +} +function getAvatarURL() { + return avatarURL; +} + function errorEmbed(errorMsg) { return new Discord.MessageEmbed() .setColor("#ff0000") @@ -288,3 +298,24 @@ function reportActionEmbed(title, messageContent, actionTakenBy) { .setTimestamp() .setFooter(versionString, avatarURL); } + +function tweetBlacklistEmbed(blacklistReason) { + return new Discord.MessageEmbed() + .setColor("#ff0000") + .setTitle("⛔ You are not allowed to tweet.") + .setDescription(`You are blacklisted for ${blacklistReason}.`) + .setTimestamp() + .setFooter(versionString, avatarURL); +} + +function wikipediaEmbed(title, shortdesc, desc, image, url) { + return new Discord.MessageEmbed() + .setColor("#ffc83d") + .setTitle(title) + .setAuthor(shortdesc) + .setDescription(desc) + .setThumbnail(image) + .setURL(url) + .setTimestamp() + .setFooter(versionString, avatarURL); +} \ No newline at end of file