├── .gitignore ├── LICENSE ├── README.md ├── bot.js ├── cmds ├── angery.js ├── ask.js ├── avatar.js ├── ban.js ├── config.js ├── edits.js ├── eval.js ├── kick.js ├── mute.js ├── ping.js ├── purge.js ├── removeroles.js ├── rolereact.js ├── send.js ├── serverinfo.js ├── shutdown.js ├── snap.js ├── suspend.js ├── test.js ├── unmute.js ├── urban.js ├── userinfo.js ├── warn.js ├── warns.js └── xkcd.js ├── data └── config-example.json ├── nodemon.json ├── package.json ├── utils.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /data/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Votyn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Space Boat 2 | Discord.js Multifunction bot primarily made for the [Space Engine Discord Server](https://discord.gg/spaceengine) 3 | ## Planned features 4 | - ~~Moderation features such as mute, kick, ban, "roleremove", and some other role addition commands.~~ 5 | - ~~Logging functionality to log user actions such as leaving and entering the server, information of which is stored in a logging channel.~~ 6 | - Role stasis, where if a user leaves the server and comes back less than a week after, their roles remain. (mainly to prevent someone from getting rid of their roles) 7 | - An "experience" and autorole system. 8 | - An adaptable "Starboard", where a channel can be made into a starboard, that listens to a set of channels given to it, and the "starring" of messages in said channel. 9 | 10 | ## Getting the official bot on your server 11 | This is currently unavailable as the bot is still highly in development! For now, you can try out the bot by installing it yourself, as shown below! 12 | 13 | ## Installation and Running of the bot. 14 | This bot requires [node.js](https://nodejs.org/en/download/), [git](https://git-scm.com/downloads), and [yarn](https://yarnpkg.com/en/docs/install). 15 | 16 | To download the **stable** version of the bot; i.e. the version the official bot is running, run the following in a terminal: 17 | ```bash 18 | git clone https://github.com/Votyn/SpaceBoat.git 19 | ``` 20 | To download the **indev** version of the bot that I am currently working on, you have to clone from the `dev` branch: 21 | ```bash 22 | git clone -b dev https://github.com/Votyn/SpaceBoat.git 23 | ``` 24 | Having downloaded the bot, download the node dependencies: 25 | ```bash 26 | yarn install 27 | ``` 28 | Then to start the bot (This uses `nodemon`): 29 | ```bash 30 | yarn start 31 | ``` 32 | If you want to run it in the background with `screen` you can use `yarn background` instead. 33 | -------------------------------------------------------------------------------- /bot.js: -------------------------------------------------------------------------------- 1 | const Discord = module.require("discord.js"); 2 | const fs = module.require("fs"); 3 | const sqlite3 = require('sqlite3').verbose(); 4 | const config = require("./data/config.json"); 5 | try { 6 | var mutes = require("./data/config.json"); 7 | } 8 | catch (error) { 9 | console.log(`${message.error}\nPlease edit the config-example.json file, and rename it as config.json!`) 10 | } 11 | 12 | try { 13 | var mutes = require("./data/mutes.json"); 14 | } 15 | catch (error) { 16 | console.log(`${error.message}`); 17 | fs.writeFileSync("./data/mutes.json", JSON.stringify({}, null, 4), err => { 18 | if (err) console.error('Error creating mutes.json file:', err); 19 | }); 20 | var mutes = require("./data/mutes.json"); 21 | console.log(`Creating new mutes.json file.`); 22 | } 23 | try { 24 | var bans = require("./data/bans.json"); 25 | } 26 | catch (error) { 27 | console.log(`${error.message}`); 28 | fs.writeFileSync("./data/bans.json", JSON.stringify({}, null, 4), err => { 29 | if (err) console.error('Error creating bans.json file:', err); 30 | }); 31 | var bans = require("./data/bans.json"); 32 | console.log(`Creating new bans.json file.`); 33 | } 34 | try { 35 | var suspendrolename = require("./data/suspendrolename.json"); // I know this is the worst way to do this, but I'm gunna be rewriting soon-ish anyway so hush 36 | } 37 | catch (error) { 38 | console.log(`${error.message}`); 39 | fs.writeFileSync("./data/suspendrolename.json", JSON.stringify({}, null, 4), err => { 40 | if (err) console.error('Error creating suspendrolename.json file:', err); 41 | }); 42 | var suspendrolename = require("./data/suspendrolename.json"); 43 | console.log(`Creating new suspendrolename.json file.`); 44 | } 45 | 46 | try { 47 | var guilds = require("./data/guilds.json"); 48 | } 49 | catch (error) { 50 | console.log(`${error.message}\nCreating new guilds.json file.`); 51 | fs.writeFileSync("./data/guilds.json", JSON.stringify({}, null, 4), err => { 52 | if (err) console.error('Error saving guilds.json file:', err); 53 | }); 54 | var guilds = require("./data/guilds.json"); 55 | } 56 | 57 | try { 58 | var rolereact = require("./data/rolereact.json"); 59 | } 60 | catch (error) { 61 | console.log(`${error.message}\nCreating new rolereact.json file.`); 62 | fs.writeFileSync("./data/rolereact.json", JSON.stringify({}, null, 4), err => { 63 | if (err) console.error('Error saving rolereact.json file:', err); 64 | }); 65 | var rolereact = require("./data/rolereact.json"); 66 | } 67 | 68 | const bot = new Discord.Client(); 69 | 70 | bot.utils = global.utils = require('./utils'); 71 | 72 | bot.commands = new Discord.Collection(); 73 | 74 | bot.colour = '678ade' 75 | bot.colours = { 76 | 'green': '43b581', 77 | 'red': 'f04947', 78 | 'orange': 'ffac33', 79 | 'purple': 'aa8ed6', 80 | 'blue': '3b88c3', 81 | 'darkblue': '226699', 82 | 'black': '292f33', 83 | 'white': 'ffffff' 84 | } 85 | bot.thanos = ['144670992768172032', '166125035092836352'] 86 | 87 | fs.readdir("./cmds/", (err, files) => { 88 | if (err) console.error(err); 89 | 90 | let jsfiles = files.filter(f => f.split(".").pop() === "js") 91 | if (jsfiles.length <= 0) { 92 | console.log("No commands to load!"); 93 | return; 94 | } 95 | 96 | console.log(`loading ${jsfiles.length} commands!`); 97 | 98 | jsfiles.forEach((f, i) => { 99 | let props = require(`./cmds/${f}`) 100 | console.log(`${i + 1}: ${f} loaded!`) 101 | bot.commands.set(props.help.name, props); 102 | }); 103 | }); 104 | 105 | bot.on('ready', () => { 106 | console.log(`${bot.user.username} switched on.`); 107 | 108 | let botGuildsIDs = Array.from(bot.guilds.keys()); 109 | for (let i in botGuildsIDs) { 110 | if (!guilds.hasOwnProperty(botGuildsIDs[i])) { 111 | console.log(`Setting up ${botGuildsIDs[i]}`); 112 | guilds[botGuildsIDs[i]] = { 113 | logChannelID: "", 114 | botChannelID: "", 115 | adminbotChannelID: "" 116 | } 117 | fs.writeFile("./data/guilds.json", JSON.stringify(guilds, null, 4), err => { 118 | if (err) console.error('Error saving guilds.json file:', err); 119 | }); 120 | console.log("Guild added to guilds.json. Please configure channelIDs."); 121 | } 122 | } 123 | 124 | for (let i in guilds) { 125 | let guild = bot.guilds.get(i) 126 | if (!guild) { 127 | console.log(`Error: Guild not found! Removing from records...`); 128 | guilds[i] = null; 129 | delete guilds[i]; 130 | fs.writeFile("./data/guilds.json", JSON.stringify(guilds, null, 4), err => { 131 | if (err) console.error('Error saving guilds.json file: ', err); 132 | }); 133 | console.log(`Removed successfully!`); 134 | continue; 135 | } 136 | if (!guilds[i].logChannelID) { 137 | console.log(`ERROR: Server [${guild.name}] does not have a logging channel!`) 138 | } 139 | if (!guilds[i].botChannelID) { 140 | console.log(`ERROR: Server [${guild.name}] does not have a specified bot channel!`) 141 | } 142 | if (!guilds[i].adminbotChannelID) { 143 | console.log(`ERROR: Server [${guild.name}] does not have an admin bot channel!`) 144 | } 145 | console.log(`Server [${guild.name}] loaded with ${guild.channels.size} channels and ${guild.memberCount} members.`); 146 | } 147 | if (mutes) { 148 | bot.setInterval(() => { 149 | for (let i in mutes) { 150 | let time = mutes[i].time; 151 | let guildID = mutes[i].guild; 152 | let guild = bot.guilds.get(guildID); 153 | let member = guild.members.get(i); 154 | let mutedRole = guild.roles.find(r => r.name === "Muted"); 155 | // check if member is still in server 156 | if (!member) { 157 | console.log('ERROR: User is not in the server anymore!'); 158 | delete mutes[i]; 159 | fs.writeFileSync("./data/mutes.json", JSON.stringify(mutes, null, 4), err => { 160 | if (err) console.error('Error saving mutes.json file: ', err); 161 | }); 162 | continue; 163 | } 164 | // check if the member has the muted role. 165 | if (!member.roles.has(mutedRole.id)) { 166 | console.log('User has been manually unmuted!'); 167 | delete mutes[i]; 168 | fs.writeFileSync("./data/mutes.json", JSON.stringify(mutes, null, 4), err => { 169 | if (err) console.error('Error saving mutes.json file: ', err); 170 | }); 171 | let logChannel = guild.channels.get(guilds[guildID].logChannelID) 172 | try { 173 | logChannel.send({ 174 | embed: new Discord.RichEmbed() 175 | .setDescription(`${member} was unmuted manually before the end of term.`) 176 | .setFooter(`ID: ${member.id}`) 177 | .setAuthor(`Member was unmuted.`, member.user.displayAvatarURL) 178 | .setTimestamp() 179 | .setColor(bot.colours.green) 180 | }) 181 | } 182 | catch (error) { 183 | if (!logChannel) console.log('No logchannel defined for this guild!'); 184 | else console.log(error); 185 | } 186 | continue; 187 | } 188 | // automatic unmute 189 | if (Date.now() > time) { 190 | // unmute 191 | member.removeRole(mutedRole); 192 | // notify console 193 | console.log(`${member.user.username} has been unmuted.`); 194 | // notify logchannel 195 | let logChannel = guild.channels.get(guilds[guildID].logChannelID) 196 | bot.utils.logChannel(bot, guildID, bot.colours.green, `Member unmuted.`, member.user, bot.user, `Automatic.`) 197 | //remove the entry 198 | mutes[i] = null; 199 | delete mutes[i]; 200 | fs.writeFileSync("./data/mutes.json", JSON.stringify(mutes, null, 4), err => { 201 | if (err) console.error('Error saving mutes.json file:', err); 202 | }); 203 | } 204 | } 205 | }); 206 | } 207 | if (bans) { 208 | bot.setInterval(() => { 209 | for (let j in bans) { 210 | let time = bans[j].time; 211 | let guildID = bans[j].guild; 212 | let guild = bot.guilds.get(guildID); 213 | guild.fetchBans() 214 | .then(Collection => { 215 | let user = Collection.get(j) 216 | if (Date.now() > time) { 217 | if (user) { 218 | guild.unban(user, `Automatic: Tempban term ended.`) 219 | try { 220 | delete bans[j]; 221 | fs.writeFile("./data/bans.json", JSON.stringify(bans, null, 4), err => { 222 | if (err) console.error('Error saving bans.json file:', err); 223 | }); 224 | } 225 | catch (error) { console.log(error) } 226 | let logChannel = guild.channels.get(guilds[guildID].logChannelID) 227 | console.log(`${user.username} has been unbanned.`); 228 | bot.utils.logChannel(bot, guildID, bot.colours.green, `Member unbanned.`, user, bot.user, `Automatically unbanned - Temporary ban term ended.`) 229 | } 230 | else { 231 | console.log(`User ${j} not found!`) 232 | try { 233 | guild.channels.get(guilds[guildID].logChannelID).send({ 234 | embed: new Discord.RichEmbed() 235 | .setDescription(`${user.username} was unbanned manually before the end of term.`) 236 | .setFooter(`ID: ${member.id}`) 237 | .setAuthor(`Member was unbanned.`, member.user.displayAvatarURL) 238 | .setTimestamp() 239 | .setColor(bot.colours.green) 240 | }) 241 | } 242 | catch (error) { 243 | // if (!logChannel) console.log('No logchannel defined for this guild!'); 244 | console.log(error); 245 | }; 246 | try { 247 | delete bans[j]; 248 | fs.writeFile("./data/bans.json", JSON.stringify(bans, null, 4), err => { 249 | if (err) console.error('Error saving bans.json file:', err); 250 | }); 251 | } 252 | catch (error) { console.log(error) } 253 | } 254 | return; 255 | } 256 | return; 257 | }) 258 | .catch(error => { console.log(error) }); 259 | continue; 260 | } 261 | }, 30000); 262 | } 263 | }); 264 | 265 | bot.db = global.db = new sqlite3.Database('./data/data.db', sqlite3.OPEN_CREATE | sqlite3.OPEN_READWRITE, (err) => { 266 | if (err) return console.error(err.message); 267 | else console.log(`Connected to Database.`); 268 | }) 269 | 270 | bot.on('message', message => { 271 | if (message.author.bot) return; 272 | if (message.mentions.everyone || message.mentions.roles.first()) { 273 | bot.utils.logChannel(bot, message.guild.id, bot.colours.purple, 'Mass ping!', message.author, '', `sent message: "${message}"`, '') 274 | } 275 | if (!(message.channel.type === "text")) return; 276 | 277 | let messageArray = message.content.split(/\s+/g); 278 | let command = messageArray[0]; 279 | let args = messageArray.slice(1); 280 | 281 | if (!command.startsWith(config.prefix)) return; 282 | 283 | let cmd = bot.commands.get(command.slice(config.prefix.length)); 284 | if (cmd) cmd.run(bot, message, args); 285 | }); 286 | 287 | bot.on('messageReactionAdd', (messageReaction, user) => { 288 | if(rolereact[messageReaction.message.id]) { 289 | let message = messageReaction.message; 290 | let emoji = rolereact[message.id].emoji; 291 | if (emoji[0] == '<') { 292 | let emojiID = emoji.split(':')[2].split('>')[0]; //custom emoji ID. 293 | //console.log(emojiID); 294 | emoji = bot.emojis.get(emojiID) 295 | } 296 | let role = message.guild.roles.get(rolereact[message.id].role); 297 | if(emoji == messageReaction.emoji) { 298 | messageReaction.users.forEach(user => { 299 | if(user === bot.user) return; 300 | try { 301 | message.guild.member(user).addRole(role, "Automated Reaction Role in #" + message.channel.name); 302 | messageReaction.remove(user); 303 | } 304 | catch (err) { 305 | if (err.name == "TypeError: Cannot read property 'addRole' of null") { 306 | try { 307 | console.log("Couldn't find " + user.username + " in the members list, trying alternative method.") 308 | message.guild.members.get(user.id).addRole(role, "Automated Reaction Role in #" + message.channel.name); 309 | messageReaction.remove(user); 310 | } catch (err) {console.log(err)} 311 | } else console.log(err)} 312 | console.log("Role added to " + user.username + "#" + user.discriminator + " from message in #" + message.channel.name); 313 | }); 314 | } 315 | } 316 | }); 317 | 318 | bot.on('guildMemberAdd', member => { 319 | let logChannel = member.guild.channels.get(guilds[member.guild.id].logChannelID) 320 | try { 321 | logChannel.send({ 322 | embed: new Discord.RichEmbed() 323 | .setThumbnail(member.user.displayAvatarURL) 324 | .setDescription(`${member} - ${member.user.tag}`) 325 | .setFooter(`ID: ${member.id}`) 326 | .setAuthor(`Member joined!`, member.user.displayAvatarURL) 327 | .setTimestamp() 328 | .setColor(bot.colours.blue) 329 | }); 330 | } 331 | catch (error) { 332 | if (!logChannel) console.log('No logchannel defined for this guild!'); 333 | else console.log(error); 334 | } 335 | console.log(`Member joined! ${member.user.tag}`); 336 | }); 337 | 338 | //below is repeat-logged when member kicked/banned. Must fix when warnings introduced. 339 | 340 | bot.on('guildMemberRemove', member => { 341 | let logChannel = member.guild.channels.get(guilds[member.guild.id].logChannelID) 342 | try { 343 | logChannel.send({ 344 | embed: new Discord.RichEmbed() 345 | .setThumbnail(member.user.displayAvatarURL) 346 | .setDescription(`${member} - ${member.user.tag}`) 347 | .setFooter(`ID: ${member.id}`) 348 | .setAuthor(`Member left.`, member.user.displayAvatarURL) 349 | .setTimestamp() 350 | .setColor(bot.colours.orange) 351 | }) 352 | } 353 | catch (error) { 354 | if (!logChannel) console.log('No logchannel defined for this guild!'); 355 | else console.log(error); 356 | } 357 | console.log(`Member left! ${member.user.tag}`); 358 | }); 359 | 360 | bot.on('guildCreate', guild => { 361 | guilds[guild.id] = { 362 | logChannelID: "", 363 | botChannelID: "", 364 | adminbotChannelID: "" 365 | } 366 | fs.writeFile("./data/guilds.json", JSON.stringify(guilds, null, 4), err => { 367 | if (err) console.error('Error saving guilds.json file:', err); 368 | }); 369 | console.log(`Joined new server! Please set up Channel IDs.`) 370 | }); 371 | 372 | bot.on('messageDelete', message => { 373 | if (!message.guild || !message.guild.channels || (!message.cleanContent && !message.attachments.first())) { 374 | return; 375 | }; 376 | 377 | let channel = message.guild.channels.find(c => c.name === "adminlog"); 378 | if (!channel) return; 379 | 380 | let embed = new Discord.RichEmbed() 381 | .setTitle('Message Deleted!') 382 | .setDescription(`\`\`\`\n${(message.cleanContent).substr(0, 1950)}\n\`\`\``) 383 | .addField('Channel', `${message.channel}`) 384 | .setColor('red') 385 | .setTimestamp(new Date()) 386 | .setFooter(`Author: @${message.author.username}#${message.author.discriminator}`, message.author.avatarURL) 387 | .setColor(bot.colours.darkblue) 388 | 389 | if (message.attachments.size > 0) { 390 | const attachment = message.attachments.first(); 391 | if (attachment.width) { 392 | embed.setImage(attachment.url); 393 | } else { 394 | embed.attachFile(attachment.url); 395 | } 396 | if (message.cleanContent) { 397 | embed.setDescription(`\`\`\`\n${(message.cleanContent).substr(0, 1950)}\n\`\`\`\n[File](${attachment.url})`) 398 | } else embed.setDescription(`[File](${attachment.url})`); 399 | } else if (message.cleanContent) embed.setDescription(`\`\`\`\n${(message.cleanContent).substr(0, 1750)}\n\`\`\``); 400 | 401 | channel.send({ embed }); 402 | }); 403 | 404 | bot.on('messageDeleteBulk', messages => { 405 | 406 | messages.tap(message => { 407 | if (!message.guild || !message.guild.channels || (!message.cleanContent && !message.attachments.first())) { 408 | return; 409 | }; 410 | let channel = message.guild.channels.find(c => c.name === "adminlog"); 411 | if (!channel) return; 412 | 413 | let embed = new Discord.RichEmbed() 414 | .setTitle('Message Deleted! (in bulk)') 415 | .setDescription(`\`\`\`\n${(message.cleanContent).substr(0, 1950)}\n\`\`\``) 416 | .addField('Channel', `${message.channel}`) 417 | .setColor(bot.colours.purple) 418 | .setTimestamp(new Date()) 419 | .setFooter(`Author: @${message.author.username}#${message.author.discriminator}`, message.author.avatarURL) 420 | 421 | if (message.attachments.size > 0) { 422 | const attachment = message.attachments.first(); 423 | if (attachment.width) { 424 | embed.setImage(attachment.url); 425 | } else { 426 | embed.attachFile(attachment.url); 427 | } 428 | if (message.cleanContent) { 429 | embed.setDescription(`\`\`\`\n${(message.cleanContent).substr(0, 1950)}\n\`\`\`\n[File](${attachment.url})`) 430 | } else embed.setDescription(`[File](${attachment.url})`); 431 | } else if (message.cleanContent) embed.setDescription(`\`\`\`\n${(message.cleanContent).substr(0, 1750)}\n\`\`\``); 432 | 433 | channel.send({ embed }); 434 | }); 435 | }); 436 | 437 | // please fix: the below will activate even if user has been banned by bot. Will result in multiple logs. 438 | 439 | // bot.on('guildBanAdd', guild, user => { 440 | // let logChannel = guild.channels.get(guilds[guild.id].logChannelID) 441 | // try { 442 | // logChannel.send({ 443 | // embed: new Discord.RichEmbed() 444 | // .setDescription(`**User:** ${user}\n`) 445 | // .setFooter(`ID: ${target.id}`) 446 | // .setAuthor(`Member Banned!`, target.user.displayAvatarURL) 447 | // .setTimestamp() 448 | // }) 449 | // } 450 | // catch (error) { 451 | // if (!logChannel) console.log('No logchannel defined for this guild!'); 452 | // else console.log(error); 453 | // } 454 | // }); 455 | 456 | //same for below. 457 | 458 | // bot.on('guildBanRemove', guild, user => { 459 | // let logChannel = guild.channels.get(guilds[guild.id].logChannelID) 460 | // try { 461 | // logChannel.send({ 462 | // embed: new Discord.RichEmbed() 463 | // .setDescription(`**User:** ${user}\n*User was unbanned manually.*`) 464 | // .setFooter(`ID: ${target.id}`) 465 | // .setAuthor(`Member Unbanned.`, target.user.displayAvatarURL) 466 | // .setTimestamp() 467 | // }) 468 | // } 469 | // catch (error) { 470 | // if (!logChannel) console.log('No logchannel defined for this guild!'); 471 | // else console.log(error); 472 | // } 473 | // remove ban length from json 474 | // }); 475 | 476 | bot.on('error', error => { 477 | console.log(`Bot has been disconnected with an error!\n${error}`) 478 | }); 479 | bot.on('disconnect', event => { 480 | console.log(`Disconnected!\n${event.reason}`) 481 | }); 482 | bot.on('destroy', () => { 483 | bot.db.close((err) => { 484 | if (err) return console.error(err.message); 485 | else console.log('Closed database connection.'); 486 | }); 487 | }) 488 | bot.login(config.token) 489 | .then('Successful Login.') 490 | .catch(error => { 491 | console.log(`Login unsuccessful!\n${error}`) 492 | }) 493 | 494 | module.exports = bot; 495 | -------------------------------------------------------------------------------- /cmds/angery.js: -------------------------------------------------------------------------------- 1 | module.exports.run = async (bot, message, args) => { 2 | if (!message.member.hasPermission("BAN_MEMBERS")) return; // Only usable by Moderators/Admins 3 | 4 | console.log(`${message.author.username} is ANGERY`) // Record event to console why not 5 | var gif 6 | if (args[0] == 'celebrity') { 7 | gif = bot.utils.randomSelection([ //randomly select from a list of gifs. 8 | `https://media.giphy.com/media/l1J9u3TZfpmeDLkD6/source.gif`, // celebrity related disappointment 9 | `https://media.giphy.com/media/y1WDIwAZRSmru/giphy.gif`, 10 | `https://media.giphy.com/media/GjR6RPcURgiL6/giphy.gif`, 11 | `https://media.giphy.com/media/QHYHhShm1sjVS/giphy.gif`, 12 | `https://media.giphy.com/media/PJfISpc3CEcaA/giphy.gif`, 13 | `https://media.giphy.com/media/GKSNQKQlQ3du0/giphy.gif`, 14 | `https://media.giphy.com/media/ilkfz8Mn5Yz7O/giphy.gif`, 15 | `https://media.giphy.com/media/KuJesxZSpHoXu/giphy.gif`, 16 | `https://media.giphy.com/media/3og0INyCmHlNylks9O/giphy.gif` 17 | ]); 18 | }else if (args[0] == 'doctor') { 19 | gif = bot.utils.randomSelection([ 20 | `https://media.giphy.com/media/IzSnJ0mFJOEjC/giphy.gif`, // Doctor Who related disappointment 21 | `https://media.giphy.com/media/Jq7y34Hgfy01y/giphy.gif`, 22 | `https://media.giphy.com/media/jAtIMGP4jwV2M/giphy.gif`, 23 | `https://media.giphy.com/media/wrezVcxv2OviU/giphy.gif`, 24 | `https://media.giphy.com/media/YcmtvvCYmn7Ec/giphy.gif`, 25 | `https://media.giphy.com/media/LU22SxTChRpvO/giphy.gif` 26 | ]); 27 | } else if (args[0] == `gordon`) { 28 | gif = bot.utils.randomSelection([ 29 | `https://media.giphy.com/media/Bcpspr9LTSvss/giphy.gif`, // Gordon Ramsey disappointment 30 | `https://media.giphy.com/media/NDz6jE0rf5S7e/giphy.gif`, 31 | `https://media.giphy.com/media/j0AYFl0muDgXe/giphy.gif`, 32 | `https://media.giphy.com/media/xfgrghdzmcptS/giphy.gif` 33 | ]); 34 | } else if (args[0] == `cartoon`) { 35 | gif = bot.utils.randomSelection([ 36 | `https://media.giphy.com/media/xUA7aKWkjTfDUREx8Y/source.gif`, //cartoon 37 | `https://media.giphy.com/media/ug9SeZBFLKHtK/giphy.gif`, 38 | `https://media.giphy.com/media/pYI1hSqUdcBiw/giphy.gif`, 39 | `https://media.giphy.com/media/a7YZNbWvIgvh6/giphy.gif`, 40 | `https://media.giphy.com/media/4w6g6yOWJYtm8/giphy.gif`, 41 | `https://media.giphy.com/media/2xPPgIRAbU0yZBMo3F/giphy.gif`, 42 | `https://media.giphy.com/media/242C34NxcI3PsqeJi9/giphy.gif`, 43 | `https://media.giphy.com/media/BWW03LrvL6W88/giphy.gif`, 44 | `https://media.giphy.com/media/ch1pcRhEb0c1y/giphy.gif`, 45 | `https://media.giphy.com/media/v5iPxSka8A03C/giphy.gif`, 46 | `https://media.giphy.com/media/DHt4WOAbjgE8w/giphy.gif`, 47 | `https://media.giphy.com/media/12XfNqI44ICkUg/giphy.gif`, 48 | `https://media.giphy.com/media/zMe5y4Lfy52Sc/giphy.gif`, 49 | `https://media.giphy.com/media/vz4rWqFNihWqk/giphy.gif`, 50 | 51 | `https://media.giphy.com/media/8YWZqADaY5YSBZO3WA/source.gif`, //final space 52 | `https://media.giphy.com/media/YU7v4hHTHdcxH0JmWf/giphy.gif`, 53 | `https://media.giphy.com/media/1BdtWbNu32vnj89ue3/giphy.gif`, 54 | `https://media.giphy.com/media/5wFjgRZWRU6W5JDBB2/giphy.gif` 55 | ]); 56 | } else if (args[0] == `finalspace`) { 57 | gif = bot.utils.randomSelection([ 58 | `https://media.giphy.com/media/8YWZqADaY5YSBZO3WA/source.gif`, //final space 59 | `https://media.giphy.com/media/YU7v4hHTHdcxH0JmWf/giphy.gif`, 60 | `https://media.giphy.com/media/1BdtWbNu32vnj89ue3/giphy.gif`, 61 | `https://media.giphy.com/media/5wFjgRZWRU6W5JDBB2/giphy.gif` 62 | ]); 63 | } else { 64 | gif = bot.utils.randomSelection([ 65 | `https://media.giphy.com/media/l1J9u3TZfpmeDLkD6/source.gif`, // celebrity related disappointment 66 | `https://media.giphy.com/media/y1WDIwAZRSmru/giphy.gif`, 67 | `https://media.giphy.com/media/GjR6RPcURgiL6/giphy.gif`, 68 | `https://media.giphy.com/media/QHYHhShm1sjVS/giphy.gif`, 69 | `https://media.giphy.com/media/PJfISpc3CEcaA/giphy.gif`, 70 | `https://media.giphy.com/media/GKSNQKQlQ3du0/giphy.gif`, 71 | `https://media.giphy.com/media/ilkfz8Mn5Yz7O/giphy.gif`, 72 | `https://media.giphy.com/media/KuJesxZSpHoXu/giphy.gif`, 73 | `https://media.giphy.com/media/3og0INyCmHlNylks9O/giphy.gif`, 74 | 75 | `https://media.giphy.com/media/IzSnJ0mFJOEjC/giphy.gif`, // Doctor Who related disappointment 76 | `https://media.giphy.com/media/Jq7y34Hgfy01y/giphy.gif`, 77 | `https://media.giphy.com/media/jAtIMGP4jwV2M/giphy.gif`, 78 | `https://media.giphy.com/media/wrezVcxv2OviU/giphy.gif`, 79 | `https://media.giphy.com/media/YcmtvvCYmn7Ec/giphy.gif`, 80 | `https://media.giphy.com/media/LU22SxTChRpvO/giphy.gif`, 81 | 82 | `https://media.giphy.com/media/Bcpspr9LTSvss/giphy.gif`, // Gordon Ramsey disappointment 83 | `https://media.giphy.com/media/NDz6jE0rf5S7e/giphy.gif`, 84 | `https://media.giphy.com/media/j0AYFl0muDgXe/giphy.gif`, 85 | `https://media.giphy.com/media/xfgrghdzmcptS/giphy.gif`, 86 | 87 | `https://media.giphy.com/media/xUA7aKWkjTfDUREx8Y/source.gif`, //cartoon 88 | `https://media.giphy.com/media/ug9SeZBFLKHtK/giphy.gif`, 89 | `https://media.giphy.com/media/pYI1hSqUdcBiw/giphy.gif`, 90 | `https://media.giphy.com/media/a7YZNbWvIgvh6/giphy.gif`, 91 | `https://media.giphy.com/media/4w6g6yOWJYtm8/giphy.gif`, 92 | `https://media.giphy.com/media/2xPPgIRAbU0yZBMo3F/giphy.gif`, 93 | `https://media.giphy.com/media/242C34NxcI3PsqeJi9/giphy.gif`, 94 | `https://media.giphy.com/media/BWW03LrvL6W88/giphy.gif`, 95 | `https://media.giphy.com/media/ch1pcRhEb0c1y/giphy.gif`, 96 | `https://media.giphy.com/media/v5iPxSka8A03C/giphy.gif`, 97 | `https://media.giphy.com/media/DHt4WOAbjgE8w/giphy.gif`, 98 | `https://media.giphy.com/media/12XfNqI44ICkUg/giphy.gif`, 99 | `https://media.giphy.com/media/zMe5y4Lfy52Sc/giphy.gif`, 100 | `https://media.giphy.com/media/vz4rWqFNihWqk/giphy.gif`, 101 | 102 | `https://media.giphy.com/media/8YWZqADaY5YSBZO3WA/source.gif`, //final space 103 | `https://media.giphy.com/media/YU7v4hHTHdcxH0JmWf/giphy.gif`, 104 | `https://media.giphy.com/media/1BdtWbNu32vnj89ue3/giphy.gif`, 105 | `https://media.giphy.com/media/5wFjgRZWRU6W5JDBB2/giphy.gif`, 106 | ]); 107 | } 108 | try {message.channel.send(gif)} // send randomlyish selected gif 109 | catch(error) {console.log(error)} 110 | try {message.delete(0).catch(err => {console.log(`Couldn't delete message`)})} 111 | catch(error) {console.log(error.message)} 112 | return; 113 | } 114 | 115 | module.exports.help = { 116 | name: "angery", 117 | usage: "angery [celebrity/doctor/gordon/cartoon/finalspace]", 118 | type: "Moderation", 119 | description: "Show that you are starting to get annoyed quickly and easily with this fun little command dedicated to the hard working moderation!" 120 | } -------------------------------------------------------------------------------- /cmds/ask.js: -------------------------------------------------------------------------------- 1 | const guilds = require("../data/guilds.json"); 2 | 3 | module.exports.run = (bot, message, args) => { 4 | if (message.channel.id === guilds[message.guild.id].botChannelID || 5 | message.channel.id === guilds[message.guild.id].adminbotChannelID) { 6 | if (Object.keys(args).length < 1) { 7 | let response = bot.utils.randomSelection([ 8 | `What?`, 9 | `I'm not telepathic you know...`, 10 | `I can't answer a question if you don't ask me one <:thinksmart:427622363547303937>`, 11 | `...`, 12 | '<:tearthonk:427621281525923842>', 13 | '<:rauf:427621360286826496>', 14 | '<:thenk:427621426514755601>', 15 | '<:oh:427621570320531456>', 16 | '<:waitwhat:427621591036198914>', 17 | '', 18 | '<:ohno:427621654684893194>', 19 | '<:thohno:427621998089338880>' 20 | ]); 21 | return message.channel.send(response); 22 | } 23 | else { 24 | randomUserID = message.mentions.members.randomKey() 25 | if (message.mentions.members.has(166125035092836352) || 26 | message.content.toLowerCase().indexOf('votyn') > 1 ) { // yes i am vain 27 | let response = bot.utils.randomSelection([ 28 | `That's not something I'm willing to discuss.`, 29 | `Why don't you ask him yourself?`, 30 | `Hmm... Not sure about that one...`, 31 | `Obviously.`, 32 | `Never.`, 33 | `Why though?`, 34 | `Not sure. Ask again later maybe?`, 35 | '<:soontm:427622707824427018>', 36 | `Not likely`, 37 | `I think so.`, 38 | `I don't think so...`, 39 | `Maybe...`, 40 | `I'm not sure.`, 41 | `Why would you ask that? <:rauf:427621360286826496>`, 42 | `I hope not!`, 43 | `I hope so...`, 44 | `Well now that you ask...`, 45 | `I would count on it.`, 46 | `Is that even a question?`, 47 | `Not on my watch!`, 48 | '<:sweats:427623000087592965>' 49 | ]); 50 | return message.channel.send(response); 51 | } 52 | else if (randomUserID) { 53 | let response = bot.utils.randomSelection([ 54 | `Why don't you ask them yourself?`, 55 | `Let them answer that question. I don't know everything after all.`, 56 | `Some questions are best left to those whom they involve.`, 57 | `Why not ask them yourself?`, 58 | `Well since you mentioned them, let them answer <:rauf:427621360286826496>`, 59 | `I don't think so...`, 60 | `Maybe they do...`, 61 | `That's not for me to say.`, 62 | `Why though?`, 63 | `Not sure. Ask again later maybe?`, 64 | `<:soontm:427622707824427018>`, 65 | `Not likely`, 66 | `I think so.`, 67 | `I'm not sure.`, 68 | `Why would you ask that? <:rauf:427621360286826496>`, 69 | `I hope not!`, 70 | `I hope so...`, 71 | `Well now that you ask...`, 72 | `I would count on it.`, 73 | `Is that even a question?`, 74 | `Not on my watch!`, 75 | ]); 76 | return message.channel.send(response); 77 | } 78 | else { // Can also be used for dm usage in future. 79 | let response = bot.utils.randomSelection([ 80 | `Hmm... Not sure about that one...`, 81 | `Obviously.`, 82 | `Never.`, 83 | `Why though?`, 84 | `Not sure. Ask again later maybe?`, 85 | `Soon:tm:`, 86 | `Not likely`, 87 | `I think so.`, 88 | `I don't think so...`, 89 | `Maybe...`, 90 | `I'm not sure.`, 91 | `Why would you ask that? <:rauf:427621360286826496>`, 92 | `I hope not!`, 93 | `I hope so...`, 94 | `Well now that you ask...`, 95 | `I would count on it.`, 96 | `Is that even a question?`, 97 | `Not on my watch!`, 98 | '<:tearthonk:427621281525923842>', 99 | '<:rauf:427621360286826496>', 100 | '<:thenk:427621426514755601>', 101 | '<:oh:427621570320531456>', 102 | '<:waitwhat:427621591036198914>', 103 | '', 104 | '<:ohno:427621654684893194>', 105 | '<:thohno:427621998089338880>', 106 | '<:sweats:427623000087592965>', 107 | `` 108 | ]); 109 | return message.channel.send(response); 110 | } 111 | } 112 | } 113 | }; 114 | 115 | 116 | module.exports.help = { 117 | name: 'ask', 118 | usage: 'ask ', 119 | type: 'Fun', 120 | description: 'Ask Space Boat a question. Don\'t expect it to be right though.' 121 | }; 122 | -------------------------------------------------------------------------------- /cmds/avatar.js: -------------------------------------------------------------------------------- 1 | const Discord = require('discord.js') 2 | module.exports.run = async (bot, message, args) => { 3 | let target = message.mentions.members.first() || message.guild.members.get(args[0]); 4 | var sendAvatar = (person) => { 5 | message.channel.send(new Discord.RichEmbed().setImage(person.displayAvatarURL).setColor(bot.colour).setDescription(`Here's <@${person.id}>'s avatar!`)) 6 | } 7 | if (!target) { 8 | if (!message.avatarURL) { 9 | sendAvatar(message.author) 10 | } 11 | } 12 | else { 13 | if (!message.avatarURL) { 14 | sendAvatar(target.user) 15 | } 16 | else { 17 | sendAvatar(target) 18 | } 19 | } 20 | } 21 | module.exports.help = { 22 | name: "avatar", 23 | usage: 'avatar [mention/user id]', 24 | type: 'Fun', 25 | description: 'Returns your or another person\'s avatar!' 26 | } -------------------------------------------------------------------------------- /cmds/ban.js: -------------------------------------------------------------------------------- 1 | const fs = module.require("fs"); 2 | const Discord = require("discord.js"); 3 | const guilds = require("../data/guilds.json") 4 | const bans = module.require("../data/bans.json"); 5 | 6 | module.exports.run = async (bot, message, args) => { 7 | if (!(message.channel.type === "text")) return; 8 | console.log("banning..."); 9 | //load logChannel 10 | const logChannel = message.guild.channels.get(guilds[message.guild.id].logChannelID); 11 | //can this user ban members? 12 | if (!message.member.hasPermission("BAN_MEMBERS")) return console.log(`${message.author.username} attempted to ban without sufficient permissions!`); 13 | //Get the mentioned member object 14 | let target = message.mentions.members.first() || message.guild.members.get(args[0]); 15 | //No member specified? 16 | if (!target) { 17 | console.log(`${message.author.username} failed to specify a target user!`); 18 | (await message.channel.send(`Please specify a target user.`)).delete(5000); 19 | return; 20 | } 21 | //Can the target member be banned? 22 | if (target.hasPermission("MANAGE_MESSAGES")) { 23 | console.log(`Error: Target user is a moderator.`); 24 | (await message.channel.send(`${target.user.username} is a moderator!`)).delete(5000); 25 | return; 26 | } 27 | 28 | // THE ACTUAL BAN BEGINS HERE 29 | 30 | // If there are no arguments after the target user is identified 31 | if (!args[1]) { 32 | //notify logchannel. 33 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member banned!`, target.user, message.author) 34 | //notify channel 35 | if(bot.thanos.includes(message.author.id)) { // For the doc 36 | await(message.channel.send(new Discord.RichEmbed() 37 | .setImage('https://media1.tenor.com/images/e36fb32cfc3b63075adf0f1843fdc43a/tenor.gif?itemid=12502580') 38 | .setColor(bot.colour) 39 | .setDescription(`${target.user.username} banned! `)) 40 | ).delete(30000) 41 | .catch(console.error); 42 | } 43 | else { 44 | message.channel.send(`${target.user.username} has been banned.`) 45 | .catch(console.error); 46 | } 47 | //notify console. 48 | console.log(`${target.user.username} has been banned!`); 49 | //ban the target user. 50 | target.ban(`Moderator: ${message.author.username}`) 51 | } 52 | 53 | // There are arguments after the user identification. 54 | if (args[1]) { 55 | //is the first argument a number? 56 | let banPeriod = args[1] * 1 57 | //if so, it's a banPeriod! 58 | if (!isNaN(banPeriod)) { 59 | //if clock supplied, check what clock. 60 | if (args[2] == 'day' || 61 | args[2] == 'days' || 62 | args[2] == 'd') { 63 | clock = 'day'; 64 | multiplier = 24; // 65 | var reason = args.splice(3).join(' ') 66 | } 67 | if (args[2] == 'hour' || 68 | args[2] == 'hours' || 69 | args[2] == 'h') { 70 | clock = 'hour'; 71 | multiplier = 1; // 72 | var reason = args.splice(3).join(' ') 73 | } 74 | if (args[2] == 'week' || 75 | args[2] == 'weeks' || 76 | args[2] == 'w') { 77 | clock = 'week'; 78 | multiplier = 168; // 24*7 79 | var reason = args.splice(3).join(' ') 80 | } 81 | if (args[2] == 'month' || 82 | args[2] == 'months' || 83 | args[2] == 'mon') { 84 | clock = 'month'; 85 | multiplier = 720; // 24*30 86 | var reason = args.splice(3).join(' ') 87 | } 88 | 89 | //if no clock supplied, or invalid clock, default to clock of hour. 90 | if (!args[2] || !clock) { 91 | var clock = 'hour'; 92 | var multiplier = 1; 93 | var reason = args.splice(2).join(' ') 94 | } 95 | 96 | let s = 's' 97 | if (banPeriod == 1) { s = '' } 98 | 99 | if (reason) { 100 | await target.send(`**You have been banned for __${banPeriod} ${clock}${s}__ with the following reason:** ${reason}`) 101 | .catch(console.error); 102 | //ban the target user 103 | target.ban(`Moderator: ${message.author.username}; Reason: ${reason}`) 104 | } 105 | if (!reason) { 106 | var reason = '' 107 | await target.send(`**You have been banned for __${banPeriod} ${clock}${s}__**`) 108 | .catch(console.error); 109 | //ban the target user 110 | target.ban(`Moderator: ${message.author.username}`) 111 | } 112 | //since it's a timed ban, create a json entry and write to bans.json 113 | bans[target.id] = { 114 | guild: message.guild.id, 115 | time: Date.now() + banPeriod * multiplier * 3600000 116 | } 117 | fs.writeFileSync("./data/bans.json", JSON.stringify(bans, null, 4), err => { 118 | if (err) throw err; 119 | }); 120 | await bot.utils.warning(bot, message.guild.id, target.id, message.author.id, `**Ban:** ${reason}`, 10, (err, result) => { 121 | if (err) { 122 | console.log(err); 123 | return message.channel.send(`Oops! I didn't manage to correctly log this.`); 124 | } 125 | else { 126 | // notify channel 127 | if(bot.thanos.includes(message.author.id)) { // For the doc 128 | message.channel.send(new Discord.RichEmbed() 129 | .setImage('https://media1.tenor.com/images/e36fb32cfc3b63075adf0f1843fdc43a/tenor.gif?itemid=12502580') 130 | .setColor(bot.colour) 131 | .setDescription(`${target.user.username} has been banned for ${banPeriod} ${clock}${s}.`)) 132 | .catch(console.error); 133 | } 134 | else { 135 | message.channel.send(`${target.user.username} has been banned for ${banPeriod} ${clock}${s}.`) 136 | .catch(console.error); 137 | } 138 | // notify logchannel 139 | var timeString = `\n**Time:** ${banPeriod} ${clock}${s}` 140 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member banned!`, target.user, message.author, reason, timeString, `\n**Warn ID:** ${result}`); 141 | } 142 | }) 143 | //notify console 144 | console.log(`${target.user.username} has been banned for ${banPeriod} ${clock}${s}.`); 145 | } 146 | 147 | else { 148 | var reason = args.splice(1).join(' ') 149 | //notify user 150 | target.send(`**You have been banned for the following reason:** ${reason}`) 151 | .catch(console.error); 152 | //ban. 153 | target.ban(`Moderator: ${message.author.username}; Reason: ${reason}`) 154 | await bot.utils.warning(bot, message.guild.id, target.id, message.author.id, `**Ban:** ${reason}`, 10, (err, result) => { 155 | if (err) { 156 | console.log(err); 157 | return message.channel.send(`Oops! I didn't manage to correctly log this.`); 158 | } 159 | else { 160 | // notify channel 161 | if(bot.thanos.includes(message.author.id)) { // For the doc 162 | message.channel.send(new Discord.RichEmbed() 163 | .setImage('https://media1.tenor.com/images/e36fb32cfc3b63075adf0f1843fdc43a/tenor.gif?itemid=12502580') 164 | .setColor(bot.colour) 165 | .setDescription(`${target.user.username} banned! `)) 166 | .catch(console.error); 167 | } 168 | else { 169 | message.channel.send(`${target.user.username} has been banned.`) 170 | .catch(console.error); 171 | } 172 | // notify logchannel 173 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member banned!`, target.user, message.author, reason, '', `\n**Warn ID:** ${result}`); 174 | } 175 | }) 176 | //notify console 177 | console.log(`${target.user.username} has been banned.`); 178 | } 179 | } 180 | return; 181 | } 182 | 183 | module.exports.help = { 184 | name: "ban", 185 | usage: "ban ", 186 | type: "Moderation", 187 | description: "bans the specified user, with an optional reason." 188 | } 189 | -------------------------------------------------------------------------------- /cmds/config.js: -------------------------------------------------------------------------------- 1 | const Discord = require('discord.js'); 2 | const guilds = require("../data/guilds.json"); 3 | const fs = module.require("fs"); 4 | 5 | module.exports.run = async (bot, message, args) => { 6 | if (!(message.channel.type === "text")) return; 7 | if (!message.member.hasPermission("MANAGE_CHANNELS")) return console.log(`${message.author.tag} attempted 'config' command with insufficient permissions.`); 8 | if (args[0] == 'logchannel') { 9 | guilds[message.channel.guild.id].logChannelID = message.channel.id 10 | fs.writeFile("./data/guilds.json", JSON.stringify(guilds, null, 4), err => { 11 | if (err) console.error('Error saving guilds.json file:', err); 12 | }); 13 | message.channel.send(`This channel has been added to the guild config as the logChannel.`) 14 | } 15 | else if (args[0] == 'botchannel') { 16 | guilds[message.channel.guild.id].botChannelID = message.channel.id 17 | fs.writeFile("./data/guilds.json", JSON.stringify(guilds, null, 4), err => { 18 | if (err) console.error('Error saving guilds.json file:', err); 19 | }); 20 | message.channel.send(`This channel has been added to the guild config as the botChannel.`) 21 | } 22 | else if (args[0] == 'adminbotchannel') { 23 | guilds[message.channel.guild.id].adminbotChannelID = message.channel.id 24 | fs.writeFile("./data/guilds.json", JSON.stringify(guilds, null, 4), err => { 25 | if (err) console.error('Error saving guilds.json file:', err); 26 | }); 27 | message.channel.send(`This channel has been added to the guild config as the adminbotChannel.`) 28 | } 29 | else { 30 | return; 31 | } 32 | } 33 | 34 | module.exports.help = { 35 | name: "config", 36 | usage: "config ", 37 | type: "Moderation", 38 | description: "configure the current server" 39 | } -------------------------------------------------------------------------------- /cmds/edits.js: -------------------------------------------------------------------------------- 1 | const Discord = module.require("discord.js"); 2 | module.exports.run = async (bot, message, args) => { 3 | if (!message.member.hasPermission("MANAGE_MESSAGES")) return; 4 | var msg; 5 | var edits; 6 | if (args[1]) { 7 | let msgid = args[1] 8 | let channelid = args[0] 9 | let channel = await message.guild.channels.get(channelid) 10 | if (channel.id == channelid) { 11 | msg = await channel.fetchMessage(msgid) 12 | if (msg.id == msgid) { 13 | edits = msg.edits 14 | } else return; 15 | } else return; 16 | } else { 17 | let msgid = args[0]; 18 | msg = await message.channel.fetchMessage(msgid) 19 | if (msg.id == msgid) { 20 | edits = msg.edits 21 | } else return; 22 | } 23 | let editarray = [] 24 | edits.forEach(e => editarray.unshift(` - ${e}`)); 25 | let embed = new Discord.RichEmbed().setAuthor('Message Edits', msg.author.displayAvatarURL) 26 | .setDescription(editarray) 27 | .setTimestamp(msg.editedAt || msg.createdAt) 28 | .setColor(bot.colour) 29 | message.channel.send(embed); 30 | } 31 | 32 | module.exports.help = { 33 | name: "edits", 34 | type: "Moderation" 35 | } -------------------------------------------------------------------------------- /cmds/eval.js: -------------------------------------------------------------------------------- 1 | const inspect = require('util').inspect; 2 | const Discord = require('discord.js'); 3 | const config = require("../data/config.json") 4 | const clean = input => { 5 | const output = typeof input === 'string' ? input : inspect(input); 6 | return output.replace(/(@|`)/g, '$1\u200b'); 7 | }; 8 | 9 | module.exports.run = async (bot, message, args) => { 10 | //only I can use this command! 11 | if (message.author.id != config.ownerid) return; 12 | 13 | const input = args.join(' '); 14 | if (!input) { 15 | (await message.channel.send('You must provide some code to evaluate!')).delete(10000); 16 | } 17 | 18 | message.delete(10000); 19 | 20 | try { 21 | const output = clean(eval(input)); 22 | message.channel.send({ 23 | embed: new Discord.RichEmbed() 24 | .addField('Input', `\`\`\`javascript\n${input.substr(0, 256)}\n\`\`\``) 25 | .addField('Output', `\`\`\`javascript\n${output.substr(0, 768)}\n\`\`\``) 26 | .setFooter(`Requested by ${message.author.tag}`) 27 | .setColor(bot.colour) 28 | }).then(m => m.delete(15000)); 29 | } catch (err) { 30 | message.channel.send(`:x: An error has occurred: \`\`\`\n${err.toString().substr(0, 1500)}\n\`\`\``); 31 | } 32 | }; 33 | 34 | module.exports.help = { 35 | name: 'eval', 36 | usage: 'eval ', 37 | type: "Private", 38 | description: 'Evaluates some JavaScript code. Restricted to bot owner.', 39 | }; -------------------------------------------------------------------------------- /cmds/kick.js: -------------------------------------------------------------------------------- 1 | const Discord = require("discord.js"); 2 | const guilds = require("../data/guilds.json") 3 | 4 | module.exports.run = async (bot, message, args) => { 5 | if (!(message.channel.type === "text")) return; 6 | console.log("kicking..."); 7 | const logChannel = message.guild.channels.get(guilds[message.guild.id].logChannelID); 8 | if (!message.member.hasPermission("KICK_MEMBERS")) return console.log(`${message.author.username} attempted to kick without sufficient permissions!`); //check permission 9 | let target = message.mentions.members.first() || message.guild.members.get(args[0]); //get mentioned member 10 | if (!target) { 11 | console.log(`${message.author.username} failed to specify a target user!`); 12 | (await message.channel.send(`Please specify a target user.`)).delete(5000); 13 | return; //check if user mentioned 14 | } 15 | if (target.hasPermission("MANAGE_MESSAGES")) { 16 | console.log(`Error: Target user is a moderator.`); 17 | (await message.channel.send(`${target.user.username} is a moderator!`)).delete(5000); 18 | return; 19 | } //Moderators cannot ban other moderators. 20 | let reason = args.splice(1).join(' '); 21 | console.log(`${target.user.username} kicked. ${reason}`); 22 | if (!reason) { 23 | response(bot, message, target); 24 | target.kick(`Moderator: ${message.author.username}`); 25 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member kicked!`, target.user, message.author) 26 | } 27 | if (reason) { 28 | // notify user 29 | target.send(`**You have been kicked for the following reason:** ${reason}`) 30 | .catch(console.error) 31 | .then(() => { 32 | // kick 33 | target.kick(`Moderator: ${message.author.username}. Reason: ${reason}`); 34 | }) 35 | await bot.utils.warning(bot, message.guild.id, target.id, message.author.id, `**Kick:** ${reason}`, 5, (err, result) => { 36 | if (err) { 37 | console.log(err); 38 | return message.channel.send(`Oops! I didn't manage to correctly log this.`); 39 | } 40 | else { 41 | // notify channel 42 | response(bot, message, target); 43 | // notify logchannel 44 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member kicked!`, target.user, message.author, reason, '', `\n**Warn ID:** ${result}`); 45 | } 46 | }) 47 | } 48 | return; 49 | } 50 | 51 | module.exports.help = { 52 | name: "kick", 53 | usage: "kick ", 54 | type: "Moderation", 55 | description: "Kicks the specified user, with an optional reason." 56 | } 57 | 58 | response = (bot, message, target) => { 59 | if(bot.thanos.includes(message.author.id)) { // For the doc 60 | message.channel.send(new Discord.RichEmbed() 61 | .setImage('https://media1.tenor.com/images/e36fb32cfc3b63075adf0f1843fdc43a/tenor.gif?itemid=12502580') 62 | .setColor(bot.colour) 63 | .setDescription(`${target.user.username} kicked! `)) 64 | .catch(console.error); 65 | } 66 | else { 67 | message.channel.send(`${target.user.username} kicked!`) 68 | .catch(console.error); 69 | } 70 | } -------------------------------------------------------------------------------- /cmds/mute.js: -------------------------------------------------------------------------------- 1 | const fs = module.require("fs"); 2 | const Discord = module.require('discord.js'); 3 | const guilds = require("../data/guilds.json"); 4 | const mutes = require("../data/mutes.json"); 5 | 6 | module.exports.run = async (bot, message, args) => { 7 | if (!(message.channel.type === "text")) return; 8 | console.log("muting..."); 9 | //import logChannel. 10 | const logChannel = message.guild.channels.get(guilds[message.guild.id].logChannelID); 11 | //check permissions. 12 | if (!message.member.hasPermission("MANAGE_MESSAGES")) return console.log(`${message.author.username} attempted to mute without sufficient permissions!`); 13 | //import target member from the message. 14 | let target = message.mentions.members.first() || message.guild.members.get(args[0]); 15 | //breaks if there is no target member. 16 | if (!target) return console.log(`${message.author.username} failed to specify a user to mute!`); 17 | //checks if target is a moderator. 18 | if (target.hasPermission("MANAGE_MESSAGES")) { 19 | console.log(`Error: ${target.user.username} is a moderator.`); 20 | (await message.channel.send(`${target.user.username} is a moderator!`)).delete(10000); 21 | return; 22 | } 23 | //searches for the role 24 | let role = message.guild.roles.find(r => r.name === "Muted"); 25 | //if no muted role exists, create it. 26 | if (!role) { 27 | try { 28 | role = await message.guild.createRole({ 29 | name: "muted", 30 | color: "#8a", 31 | permissions: [] 32 | }); 33 | 34 | message.guild.channels.forEach(async (channel, id) => { 35 | await channel.overwritePermissions(role, { 36 | SEND_MESSAGES: false, 37 | ADD_REACTIONS: false 38 | }); 39 | }); 40 | console.log('Created muted role'); 41 | } catch (error) { 42 | console.log(error.stack); 43 | } 44 | } 45 | //makes sure that the bot's highest role is above the muted role. 46 | if (message.guild.me.highestRole.comparePositionTo(role) < 1) { 47 | console.log(`ERROR: Cannot assign Muted role!`); 48 | try { 49 | logChannel.send(`ERROR: Cannot assign Muted role!`); 50 | } 51 | catch (error) { 52 | console.log('No logchannel defined for this guild!'); 53 | (await message.channel.send('Please configure a logging channel!')).delete(10000); 54 | } 55 | return; 56 | } 57 | //checks if member already muted. 58 | if (target.roles.has(role.id)) { 59 | console.log(`${target.user.username} already muted!`); 60 | (await message.channel.send(`${target.user.username} already muted!`)).delete(10000); 61 | return; 62 | } 63 | 64 | // THE ACTUAL MUTE BEGINS HERE 65 | 66 | // There are no arguments after the target user is identified 67 | if (!args[1]) { 68 | //notify logchannel. 69 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member muted!`, target.user, message.author) 70 | //notify channel 71 | message.channel.send(`${target.user.username} has been muted.`); 72 | //notify console. 73 | console.log(`${target.user.username} has been muted.`); 74 | //mute the target user. 75 | await target.addRole(role, `Moderator: ${message.author.username}`).catch(err => { console.error(err) }); 76 | } 77 | 78 | // There are arguments after the user identification. 79 | if (args[1]) { 80 | //is the first argument a number? 81 | let muteLength = args[1] * 1 82 | //if so, it's a muteLength! 83 | if (!isNaN(muteLength)) { 84 | //if clock supplied, check what clock. 85 | if (args[2] == 'seconds' || 86 | args[2] == 'second' || 87 | args[2] == 'secs' || 88 | args[2] == 'sec' || 89 | args[2] == 's') { 90 | clock = 'second'; 91 | multiplier = 1; //filesave multiplies by 1000 by default. 92 | var reason = args.splice(3).join(' ') 93 | } 94 | if (args[2] == 'minutes' || 95 | args[2] == 'minute' || 96 | args[2] == 'mins' || 97 | args[2] == 'min' || 98 | args[2] == 'm') { 99 | clock = 'minute'; 100 | multiplier = 60; //filesave multiplies by 1000 by default. 101 | var reason = args.splice(3).join(' ') 102 | } 103 | if (args[2] == 'hours' || 104 | args[2] == 'hour' || 105 | args[2] == 'h') { 106 | clock = 'hour'; 107 | multiplier = 3600; //60 * 60 108 | var reason = args.splice(3).join(' ') 109 | } 110 | if (args[2] == 'days' || 111 | args[2] == 'day' || 112 | args[2] == 'd') { 113 | clock = 'day'; 114 | multiplier = 86400; //60 * 60 * 24 115 | var reason = args.splice(3).join(' ') 116 | } 117 | if (args[2] == 'weeks' || 118 | args[2] == 'week' || 119 | args[2] == 'w') { 120 | clock = 'week'; 121 | multiplier = 604800; //60 * 60 * 24 * 7 122 | var reason = args.splice(3).join(' ') 123 | } 124 | //if no clock supplied, or invalid clock, default to clock of minute. 125 | if (!args[2] || !clock) { 126 | var clock = 'minute'; 127 | var multiplier = 60; 128 | var reason = args.splice(2).join(' ') 129 | } 130 | 131 | let s = 's' 132 | if (muteLength == 1) { s = '' } 133 | 134 | if (reason) { 135 | target.send(`**You have been muted for __${muteLength}__ ${clock}${s} the following reason:** ${reason}`) 136 | .catch(console.error); 137 | //mute the target user 138 | await target.addRole(role, `Moderator: ${message.author.username}; Reason: ${reason}`).catch(err => { console.error(err) }); 139 | } 140 | if (!reason) { 141 | var reason = '' 142 | //mute the target user 143 | await target.addRole(role, `Moderator: ${message.author.username}`).catch(err => { console.error(err) }); 144 | } 145 | //since it's a timed mute, create a json entry and write to mutes.json 146 | mutes[target.id] = { 147 | guild: message.guild.id, 148 | time: Date.now() + muteLength * multiplier * 1000 149 | } 150 | fs.writeFileSync("./data/mutes.json", JSON.stringify(mutes, null, 4), err => { 151 | if (err) throw err; 152 | }); 153 | //log as warning. 154 | await bot.utils.warning(bot, message.guild.id, target.id, message.author.id, `**Mute:** ${reason}`, 3, (err, result) => { 155 | if (err) { 156 | console.log(err); 157 | return message.channel.send(`Oops! I didn't manage to correctly log this.`); 158 | } 159 | else { 160 | // notify channel 161 | message.channel.send(`${target.user.username} has been muted for ${muteLength} ${clock}${s}.`); 162 | // notify logchannel 163 | var timeString = `\n**Time:** ${muteLength} ${clock}${s}` 164 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member muted!`, target.user, message.author, reason, timeString, `\n**Warn ID:** ${result}`); 165 | } 166 | }) 167 | //notify console 168 | console.log(`${target.user.username} has been muted for ${muteLength} ${clock}${s}.`); 169 | } 170 | 171 | else { 172 | let reason = args.splice(1).join(' ') 173 | //notify user 174 | target.send(`**You have been muted for the following reason:** ${reason}`) 175 | .catch(console.error); 176 | //apply the muted role. 177 | await target.addRole(role, `Moderator: ${message.author.username}. Reason: ${reason}`).catch(err => { console.error(err) }); 178 | //log as warning. 179 | await bot.utils.warning(bot, message.guild.id, target.id, message.author.id, `**Mute:** ${reason}`, 3, (err, result) => { 180 | if (err) { 181 | console.log(err); 182 | return message.channel.send(`Oops! I didn't manage to correctly log this.`); 183 | } 184 | else { 185 | // notify channel 186 | message.channel.send(`${target.user.username} has been muted`); 187 | // notify logchannel 188 | bot.utils.logChannel(bot, message.guild.id, bot.colours.red, `Member muted!`, target.user, message.author, reason, '', `\n**Warn ID:** ${result}`); 189 | } 190 | }) 191 | //notify console 192 | console.log(`${target.user.username} has been muted.`); 193 | } 194 | } 195 | return; 196 | } 197 | 198 | module.exports.help = { 199 | name: "mute", 200 | usage: "mute