From 8b2c262c37128797d71fdf13de07e30df41c3b60 Mon Sep 17 00:00:00 2001 From: MrTech999 <48654513+MrTech999@users.noreply.github.com> Date: Mon, 9 Mar 2020 22:20:45 +0000 Subject: [PATCH 01/37] Added a dogfact and carfact command, while also improving index.js so it actually gives reasons for it shitting itself. --- index.js | 86 ++++++++++++++++++++++++++++++++++++++--- src/commands/catfact.js | 23 +++++++++++ src/commands/dogfact.js | 23 +++++++++++ 3 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 src/commands/catfact.js create mode 100644 src/commands/dogfact.js diff --git a/index.js b/index.js index 9b559ff..a6db338 100644 --- a/index.js +++ b/index.js @@ -6,11 +6,40 @@ const chalk = require('chalk'); const DBL = require("dblapi.js"); const client = new Discord.Client(); +try { client.config = require('./config'); +} catch (err) { + console.log('Unable to load config.js \n', err); + process.exit(); +} + +try{ client.version = require('./version.json'); +} catch (err) { + console.log('Unable to load the version file. \n', err); + process.exit(); +} + +try{ client.logger = require('./src/modules/Logger'); +} catch (err) { + console.log('Unable to load the logger. \n', err); + process.exit(); +} + +try{ require("./src/modules/functions")(client); +} catch (err) { + console.log('Unable to load the functions. \n', err); + process.exit(); +} + +try{ client.logger.setClient(client); +} catch (err) { + console.log('Unable to initiate the logger. \n', err); + process.exit(1); +} if(process.env['USER'] != 'container') { client.devmode = true; @@ -19,12 +48,37 @@ if(process.env['USER'] != 'container') { const dblapi = new DBL(client.config.dblkey, client); } +try{ client.commands = new Enmap(); -client.aliases = new Enmap(); -client.settings = new Enmap({name: 'settings'}); -client.blacklist = new Enmap({name: 'blacklist'}); +} catch (err) { + console.log('Failed to create the commands database. \n', err); + process.exit(); +} +try{ +client.aliases = new Enmap(); +} catch (err) { + console.log('Unable to create the aliases database. \n', err); + process.exit(); +} + +try{ +client.settings = new Enmap({name: 'settings'}); +} catch (err) { + console.log('Unable to make the settings database. \n', err); + process.exit(); +} + +try{ +client.blacklist = new Enmap({name: 'blacklist'}); +} catch (err) { + console.log('Unable to create the blacklist database. \n', err); + process.exit(1); +} + +try{ const init = async () => { + try{ const cmdFiles = await readdir("./src/commands/"); client.logger.info(`Loading ${cmdFiles.length} commands.`); cmdFiles.forEach(file => { @@ -36,7 +90,12 @@ const init = async () => { console.log(response); }; }); +} catch (err) { + console.log('Unable to load Woomys commands. \n', err); + process.exit(1); +} + try{ const evtFiles = await readdir("./src/events/"); client.logger.info(`Loading ${evtFiles.length} events.`); evtFiles.forEach(file => { @@ -47,18 +106,35 @@ const init = async () => { const event = require(`./src/events/${file}`); client.on(eventName, event.bind(null, client)); }); +} catch (err) { + console.log('Unable to load Woomy events. \n', err); + process.exit(); +} + try{ client.levelCache = {}; for (let i = 0; i < client.config.permLevels.length; i++) { const thisLevel = client.config.permLevels[i]; client.levelCache[thisLevel.name] = thisLevel.level; }; +} catch (err) { + console.log('Unable to enable the levelCache. \n', err); + process.exit(); +} + try{ if(client.devmode === true) { client.login(client.config.devtoken); } else { client.login(client.config.token); }; +} catch (err) { + console.log('Unable to login to Discord. \n', err); + process.exit(1); +} }; - -init(); \ No newline at end of file +init(); +} catch (err) { + console.log('Failed to initiate Woomy. \n', err); + process.exit(1); +} \ No newline at end of file diff --git a/src/commands/catfact.js b/src/commands/catfact.js new file mode 100644 index 0000000..7505a1b --- /dev/null +++ b/src/commands/catfact.js @@ -0,0 +1,23 @@ +const request = require("request"); + +exports.run = async (bot, message, args) => { + request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { + if (error) throw new Error(error); + message.channel.send(`**Did you know?**\n ${body.facts[0]}`); + }); +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["kittenfact"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "catfact", + category: "User", + description: "Sends a fun fact about a cat.", + usage: "catfact/kittenfact" + }; diff --git a/src/commands/dogfact.js b/src/commands/dogfact.js new file mode 100644 index 0000000..ae0ef94 --- /dev/null +++ b/src/commands/dogfact.js @@ -0,0 +1,23 @@ +const request = require("request"); + +exports.run = async (bot, message, args) => { + request({ uri: "https://dog-api.kinduff.com/api/facts", json: true }, (error, response, body) => { + if (error) throw new Error(error); + message.channel.send(`**Did you know?**\n ${body.facts[0]}`); + }); +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["pupfact"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "dogfact", + category: "User", + description: "Sends a fun fact about a doggo.", + usage: "dogfact/pupfact" + }; From 1c21161500f2b733e6ee2555385ec2bf43fa4096 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 09:37:48 +1100 Subject: [PATCH 02/37] Bots have a bot badge, avatars are larger --- changes.txt | 2 ++ src/commands/about.js | 2 +- src/commands/avatar.js | 2 +- src/commands/ban.js | 2 +- src/commands/giverole.js | 2 +- src/commands/hackban.js | 2 +- src/commands/kick.js | 2 +- src/commands/nowplaying.js | 2 +- src/commands/purge.js | 2 +- src/commands/servericon.js | 2 +- src/commands/serverinfo.js | 2 +- src/commands/softban.js | 2 +- src/commands/takerole.js | 2 +- src/commands/userinfo.js | 14 +++++++++++--- 14 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 changes.txt diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..daa5b88 --- /dev/null +++ b/changes.txt @@ -0,0 +1,2 @@ +Links to avatars now lead to the original file size +Bots now get a bot badge in the userinfo command diff --git a/src/commands/about.js b/src/commands/about.js index 02b2c2c..5c1538f 100644 --- a/src/commands/about.js +++ b/src/commands/about.js @@ -28,7 +28,7 @@ exports.run = (client, message) => { embed = new Discord.MessageEmbed(); embed.setTitle(`Woomy`); embed.setColor(client.embedColour(message)); - embed.setThumbnail(client.user.avatarURL({format: "png", dynamic: true})) + embed.setThumbnail(client.user.avatarURL({format: "png", dynamic: true, size: 2048})) embed.addField( "General:", `• users: \`${client.users.cache.size}\`\n• channels: \`${client.channels.cache.size}\`\n• servers: \`${client.guilds.cache.size}\`\n• commands: \`${client.commands.size}\`\n• uptime: \`${duration}\``,true ); diff --git a/src/commands/avatar.js b/src/commands/avatar.js index 1bbb9e4..5832be2 100644 --- a/src/commands/avatar.js +++ b/src/commands/avatar.js @@ -19,7 +19,7 @@ exports.run = (client, message, args) => { user = users[0]; user = user.user; } - message.channel.send(`**${user.tag}'s** avatar is: ${user.avatarURL({format: "png", dynamic: true})}`); + message.channel.send(`**${user.tag}'s** avatar is: ${user.avatarURL({format: "png", dynamic: true, size: 2048})}`); }; exports.conf = { diff --git a/src/commands/ban.js b/src/commands/ban.js index fe403c2..affa882 100644 --- a/src/commands/ban.js +++ b/src/commands/ban.js @@ -58,7 +58,7 @@ exports.run = async (client, message, args) => { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#BC0057"); - embed.setAuthor("User banned!", user.user.avatarURL({format: "png", dynamic: true})); + embed.setAuthor("User banned!", user.user.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription( `• User: ${user.user.tag} (${user.user.id})\n• Mod: ${message.author} (${message.author.id})\n• Reason: ${reason}` ); diff --git a/src/commands/giverole.js b/src/commands/giverole.js index 356cd74..f62a055 100644 --- a/src/commands/giverole.js +++ b/src/commands/giverole.js @@ -59,7 +59,7 @@ exports.run = async (client, message, [member, ...role2add], query) => { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#00c09a"); - embed.setAuthor("Role given:", user.user.avatarURL({format: "png", dynamic: true})); + embed.setAuthor("Role given:", user.user.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription(`‏‏‎• User: ${user} (${user.user.id})\n‏‏‎• Mod: ${message.author} (${message.author.id})\n‏‏‎• Role: ${gRole}`) try { channel.send({ embed }); diff --git a/src/commands/hackban.js b/src/commands/hackban.js index c18b880..ff4d1cb 100644 --- a/src/commands/hackban.js +++ b/src/commands/hackban.js @@ -31,7 +31,7 @@ exports.run = async (client, message, args) => { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#BC0057"); - embed.setAuthor("User banned!", user.avatarURL({format: "png", dynamic: true})); + embed.setAuthor("User banned!", user.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription( `• User: ${user.tag} (${user.id})\n• Mod: ${message.author} (${message.author.id})\n• Reason: ${reason}` ); diff --git a/src/commands/kick.js b/src/commands/kick.js index 0002f44..9070a98 100644 --- a/src/commands/kick.js +++ b/src/commands/kick.js @@ -58,7 +58,7 @@ if (settings.modlogsChannel !== "off") { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#fd0061"); - embed.setAuthor("User kicked!", user.user.avatarURL({format: "png", dynamic: true})); + embed.setAuthor("User kicked!", user.user.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription( `• User: ${user.user.tag} (${user.user.id})\n• Mod: ${message.author} (${message.author.id})\n• Reason: ${reason}` ); diff --git a/src/commands/nowplaying.js b/src/commands/nowplaying.js index 9aa0487..e94f71a 100644 --- a/src/commands/nowplaying.js +++ b/src/commands/nowplaying.js @@ -23,7 +23,7 @@ exports.run = async (client, message) => { embed.setDescription(`**[${song.title}](https://www.youtube.com/watch?v=${song.id})**`) embed.addField("Channel:", song.author, true) embed.addField("Time:", timestamp, true) - embed.setFooter("Requested by " + song.requestedBy.tag, song.requestedBy.avatarURL({format: "png", dynamic: true})) + embed.setFooter("Requested by " + song.requestedBy.tag, song.requestedBy.avatarURL({format: "png", dynamic: true, size: 2048})) message.channel.send(embed) }; diff --git a/src/commands/purge.js b/src/commands/purge.js index 406bf64..79cf320 100644 --- a/src/commands/purge.js +++ b/src/commands/purge.js @@ -34,7 +34,7 @@ exports.run = async (client, message, args, level) => { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#a62019"); - embed.setAuthor(`${amount} messages purged!`, message.author.avatarURL({format: "png", dynamic: true})); + embed.setAuthor(`${amount} messages purged!`, message.author.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription(`• Channel: ${message.channel.name} (${message.channel.id})\n• Mod: ${message.author} (${message.author.id})\n• Amount: \`${amount}\``) try { channel.send({ embed }); diff --git a/src/commands/servericon.js b/src/commands/servericon.js index 5a22748..2eb44c4 100644 --- a/src/commands/servericon.js +++ b/src/commands/servericon.js @@ -1,5 +1,5 @@ exports.run = (client, message) => { - message.channel.send(`**${message.guild}'s** icon is:\n${message.guild.iconURL({format: "png", dynamic: true})}`) + message.channel.send(`**${message.guild}'s** icon is:\n${message.guild.iconURL({format: "png", dynamic: true, size: 2048})}`) }; exports.conf = { diff --git a/src/commands/serverinfo.js b/src/commands/serverinfo.js index 41c8b0c..89c2230 100644 --- a/src/commands/serverinfo.js +++ b/src/commands/serverinfo.js @@ -78,7 +78,7 @@ exports.run = (client, message) => { .setColor(message.guild.member(client.user).displayHexColor) .setTitle(guild.name) .setDescription(`${badges}• **ID:** ${guild.id}\n• **Owner:** ${guild.owner}\n• **Region:** ${guild.region.toProperCase()}\n• **Boosts:** ${boosts}\n• **Members:** ${members}\n• **Channels:** ${channelString}\n• **Roles:** ${roles}\n• **Emojis:** ${emojiString}\n• **Creation date:** ${guild.createdAt}`) - .setThumbnail(message.guild.iconURL({format: "png", dynamic: true})); + .setThumbnail(message.guild.iconURL({format: "png", dynamic: true, size: 2048})); message.channel.send(embed); }; diff --git a/src/commands/softban.js b/src/commands/softban.js index ca95e60..1b602c5 100644 --- a/src/commands/softban.js +++ b/src/commands/softban.js @@ -71,7 +71,7 @@ exports.run = async (client, message, args) => { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#F38159"); - embed.setAuthor("User softbanned!", user.user.avatarURL({format: "png", dynamic: true})); + embed.setAuthor("User softbanned!", user.user.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription( `• User: ${user.user.tag} (${user.user.id})\n• Mod: ${message.author} (${message.author.id})\n• Days cleared: ${days}` ); diff --git a/src/commands/takerole.js b/src/commands/takerole.js index 4a11fa6..408d0e3 100644 --- a/src/commands/takerole.js +++ b/src/commands/takerole.js @@ -59,7 +59,7 @@ exports.run = async (client, message, [member, ...role2add], query) => { if (channel) { let embed = new Discord.MessageEmbed(); embed.setColor("#008369"); - embed.setAuthor("Role taken:", user.user.avatarURL({format: "png", dynamic: true})); + embed.setAuthor("Role taken:", user.user.avatarURL({format: "png", dynamic: true, size: 2048})); embed.setDescription(`‏‏‎• User: ${user} (${user.user.id})\n‏‏‎• Mod: ${message.author} (${message.author.id})\n‏‏‎• Role: ${gRole}`) try { channel.send({ embed }); diff --git a/src/commands/userinfo.js b/src/commands/userinfo.js index 1ad7ec0..f84b40a 100644 --- a/src/commands/userinfo.js +++ b/src/commands/userinfo.js @@ -40,7 +40,15 @@ exports.run = (client, message, args) => { }; if(user.user.id == message.guild.ownerID) { - badges = "<:owner:685703193694306331>\n" + badges += "<:owner:685703193694306331>" + } + + if(user.user.bot) { + badges += "<:bot:686489601678114859>" + } + + if(badges.length > 0) { + badges += "\n" } createdTimestamp = user.user.createdTimestamp; @@ -61,13 +69,13 @@ exports.run = (client, message, args) => { id = user.user.id; tag = user.user.tag; colour = user.displayHexColor; - avurl = user.user.avatarURL({format: "png", dynamic: true}); + avurl = user.user.avatarURL({format: "png", dynamic: true, size: 2048}); createdAt = user.user.createdAt; } else { id = user.id; tag = user.tag; colour = ["#ff9d68", "#ff97cb", "#d789ff", "#74FFFF"].random(); - avurl = user.avatarURL({format: "png", dynamic: true}); + avurl = user.avatarURL({format: "png", dynamic: true, size: 2048}); createdAt = user.createdAt; }; From a91d4774eb5057583b7259b5042821f1df0dc945 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Mon, 9 Mar 2020 22:58:41 +0000 Subject: [PATCH 03/37] Update index.js - modified code a bit --- index.js | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/index.js b/index.js index a6db338..6adb8b7 100644 --- a/index.js +++ b/index.js @@ -9,35 +9,35 @@ const client = new Discord.Client(); try { client.config = require('./config'); } catch (err) { - console.log('Unable to load config.js \n', err); + console.log('Could not load config.js. \n', err); process.exit(); } try{ client.version = require('./version.json'); } catch (err) { - console.log('Unable to load the version file. \n', err); + console.log('Could not load version.json. \n', err); process.exit(); } try{ client.logger = require('./src/modules/Logger'); } catch (err) { - console.log('Unable to load the logger. \n', err); + console.log('Could not load Logger.js. \n', err); process.exit(); } try{ require("./src/modules/functions")(client); } catch (err) { - console.log('Unable to load the functions. \n', err); + console.log('Could not load functions.js. \n', err); process.exit(); } try{ client.logger.setClient(client); } catch (err) { - console.log('Unable to initiate the logger. \n', err); + console.log('Logger failed to initialize. \n', err); process.exit(1); } @@ -51,34 +51,33 @@ if(process.env['USER'] != 'container') { try{ client.commands = new Enmap(); } catch (err) { - console.log('Failed to create the commands database. \n', err); + console.log('Failed to create the commands map. \n', err); process.exit(); } try{ client.aliases = new Enmap(); } catch (err) { - console.log('Unable to create the aliases database. \n', err); + console.log('Failed to create the aliases map. \n', err); process.exit(); } try{ client.settings = new Enmap({name: 'settings'}); } catch (err) { - console.log('Unable to make the settings database. \n', err); + console.log('Failed to initialize the settings database. \n', err); process.exit(); } try{ client.blacklist = new Enmap({name: 'blacklist'}); } catch (err) { - console.log('Unable to create the blacklist database. \n', err); + console.log('Failed to initialize the blacklist database. \n', err); process.exit(1); } try{ const init = async () => { - try{ const cmdFiles = await readdir("./src/commands/"); client.logger.info(`Loading ${cmdFiles.length} commands.`); cmdFiles.forEach(file => { @@ -90,12 +89,7 @@ const init = async () => { console.log(response); }; }); -} catch (err) { - console.log('Unable to load Woomys commands. \n', err); - process.exit(1); -} - try{ const evtFiles = await readdir("./src/events/"); client.logger.info(`Loading ${evtFiles.length} events.`); evtFiles.forEach(file => { @@ -106,10 +100,6 @@ const init = async () => { const event = require(`./src/events/${file}`); client.on(eventName, event.bind(null, client)); }); -} catch (err) { - console.log('Unable to load Woomy events. \n', err); - process.exit(); -} try{ client.levelCache = {}; @@ -118,7 +108,7 @@ const init = async () => { client.levelCache[thisLevel.name] = thisLevel.level; }; } catch (err) { - console.log('Unable to enable the levelCache. \n', err); + console.log('Level cache failed to initialize. \n', err); process.exit(); } @@ -135,6 +125,6 @@ const init = async () => { }; init(); } catch (err) { - console.log('Failed to initiate Woomy. \n', err); + console.log('Initialization failed. \n', err); process.exit(1); -} \ No newline at end of file +} From 3af8fdb2b090912564aceae480c00de93621e8aa Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 10:11:53 +1100 Subject: [PATCH 04/37] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 693f553..d0fde98 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Woomy -Woomy is a all-purpose discord bot built off the [guidebot](https://github.com/AnIdiotsGuide/guidebot) base and coded in node.js using discord.js. +Woomy is a all-purpose discord bot built off the [guidebot](https://github.com/AnIdiotsGuide/guidebot) base and coded in node.js using discord.js. # How to use The easiest way to use Woomy is to invite it to your server with [this link.](https://discordapp.com/oauth2/authorize?client_id=435961704145485835&permissions=2134240503&scope=bot) It is hosted 24/7 and automatically updates itself when a new release is made available, making sure you always get the newest features. -Self hosting is generally not recommended, but instructions are provided below if you still wish to do so. Woomy's code will need to be modified before it will run on your machine. +You can also self-host! Some modificatiomns to the code will need to be made before Woomy will run on your machine, but anyone who can read errors will figure out what needs to be changed pretty quickly :P # Requirements - git - node.js v12.0.0 or higher - node-gyp build tools -- ffmpeg +- ffmpeg (or ffmpeg-static) # Installation - Clone Woomy to your machine @@ -18,4 +18,4 @@ Self hosting is generally not recommended, but instructions are provided below i - Open config.js in your code editor and insert all the required information # Contributing -If you wish to contribute to Woomy, please fork the repository and open a pull request. +If you wish to contribute to Woomy, please fork the repository and open a pull request. Any contribution is appreciated <3 From 85be37097d0da55656d746e0e6ee2271edf7a7b6 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 10:17:32 +1100 Subject: [PATCH 05/37] Update configTemplate.js --- configTemplate.js | 129 +++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/configTemplate.js b/configTemplate.js index a8adf42..3828ed8 100644 --- a/configTemplate.js +++ b/configTemplate.js @@ -1,68 +1,69 @@ const config = { - // ID's - "owners": ["433790467830972417", "324937993972350976"], - - // Tokens - "token": "", - "devtoken": "", - "ytkey": "", - "dblkey": "", - - // Default per-server settings - "defaultSettings" : { - "prefix": "~", - "devprefix": "!", - "modRole": "None set", - "adminRole": "None set", - "mutedRole": "None set", - "autorole": "off", - "welcomeChannel": "off", - "welcomeMessage": "off", - "leaveMessage": "off", - "chatlogsChannel": "off", - "modlogsChannel": "off", - "raidMode": "off", - "raidModeStrict": "off", - "blacklisted": "ARRAY", - "botChannels": "ARRAY", - "AFK": "ARRAY", - "SAR": "ARRAY" + // ID's + "owners": [], // Adding your ID here will give you access to dangerous commands like eval. Please be careful with who you add here! Eval can be used to modify the host machine. + + // Tokens + "token": "", // Your bot's token. + "devtoken": "", // (optional) another token, meant for a bot used for development + "ytkey": "", // Youtube API key, needed for music searching to work + "dblkey": "", // top.gg key, sends bot statistics to top.gg. You do not need this. + + // Default per-server settings + "defaultSettings" : { + "prefix": "~", + "devprefix": "!", + "modRole": "None set", + "adminRole": "None set", + "mutedRole": "None set", + "autorole": "off", + "welcomeChannel": "off", + "welcomeMessage": "off", + "leaveMessage": "off", + "chatlogsChannel": "off", + "modlogsChannel": "off", + "raidMode": "off", + "raidModeStrict": "off", + "blacklisted": "ARRAY", + "botChannels": "ARRAY", + "AFK": "ARRAY", + "SAR": "ARRAY", + "customCommands": "ARRAY", + }, + + // Perm levels + permLevels: [ + { level: 0, + name: "User", + check: () => true }, - - // Perm levels - permLevels: [ - { level: 0, - name: "User", - check: () => true - }, - - { level: 1, - name: "Moderator", - check: (message) => { - try { - if (message.member.roles.has(message.settings.modRole)) return true; - } catch (e) { - return false; - } + + { level: 1, + name: "Moderator", + check: (message) => { + try { + if (message.member.roles.cache.has(message.settings.modRole)) return true; + } catch (e) { + return false; } - }, - - { level: 2, - name: "Administrator", - check: (message) => { - try { - if (message.member.roles.has(message.settings.adminRole)) return true; - } catch (e) { - return false; - } + } + }, + + { level: 2, + name: "Administrator", + check: (message) => { + try { + if (message.member.roles.cache.has(message.settings.adminRole) || message.member.permissions.has("ADMINISTRATOR")) return true; + } catch (e) { + return false; } - }, - - { level: 3, - name: "Server Owner", - check: (message) => message.channel.type === "text" ? (message.guild.ownerID === message.author.id ? true : false) : false - }, - ] - }; - - module.exports = config; \ No newline at end of file + } + }, + + { level: 3, + name: "Server Owner", + check: (message) => message.channel.type === "text" ? (message.guild.ownerID === message.author.id ? true : false) : false + }, + ] +}; + +module.exports = config; From 1bf10ccc0c859df819e7571cb8e0d5cc20d872ab Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 10:57:54 +1100 Subject: [PATCH 06/37] Fixed catfact --- src/commands/catfact.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/catfact.js b/src/commands/catfact.js index 7505a1b..97063fc 100644 --- a/src/commands/catfact.js +++ b/src/commands/catfact.js @@ -3,7 +3,7 @@ const request = require("request"); exports.run = async (bot, message, args) => { request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { if (error) throw new Error(error); - message.channel.send(`**Did you know?**\n ${body.facts[0]}`); + message.channel.send(`**Did you know?**\n ${body.data[0].fact}`); }); }; From e2403b6cbec1a347aaf3eb18552c4e6616e3bad9 Mon Sep 17 00:00:00 2001 From: Terryiscool160 <48654513+Terryiscool160@users.noreply.github.com> Date: Tue, 10 Mar 2020 00:12:00 +0000 Subject: [PATCH 07/37] Fixes. Put CatFact and DogFact into the "Fun" category while also adding a discord disconnect and reconnect logger. --- src/commands/catfact.js | 4 ++-- src/commands/dicerole.js | 27 +++++++++++++++++++++++++++ src/commands/dogfact.js | 2 +- src/events/disconnect.js | 3 +++ src/events/reconnection.js | 3 +++ 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/commands/dicerole.js create mode 100644 src/events/disconnect.js create mode 100644 src/events/reconnection.js diff --git a/src/commands/catfact.js b/src/commands/catfact.js index 7505a1b..18fc87e 100644 --- a/src/commands/catfact.js +++ b/src/commands/catfact.js @@ -3,7 +3,7 @@ const request = require("request"); exports.run = async (bot, message, args) => { request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { if (error) throw new Error(error); - message.channel.send(`**Did you know?**\n ${body.facts[0]}`); + message.channel.send(`**Did you know?**\n ${body.data[0].facts}`); }); }; @@ -17,7 +17,7 @@ exports.conf = { exports.help = { name: "catfact", - category: "User", + category: "Fun", description: "Sends a fun fact about a cat.", usage: "catfact/kittenfact" }; diff --git a/src/commands/dicerole.js b/src/commands/dicerole.js new file mode 100644 index 0000000..569f381 --- /dev/null +++ b/src/commands/dicerole.js @@ -0,0 +1,27 @@ +exports.run = async (bot, message, args) => { + if (args.length === 0) { + message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + } else { + if (args[0].match(/^\d+$/)) { + message.channel.send(`🎲 The dice landed on ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}.`); + } else { + message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + } + } + }; + + exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["diceroll"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "dice", + category: "Fun", + description: "Rolls a dice.", + usage: "dice" + }; + \ No newline at end of file diff --git a/src/commands/dogfact.js b/src/commands/dogfact.js index ae0ef94..dc6bf7c 100644 --- a/src/commands/dogfact.js +++ b/src/commands/dogfact.js @@ -17,7 +17,7 @@ exports.conf = { exports.help = { name: "dogfact", - category: "User", + category: "Fun", description: "Sends a fun fact about a doggo.", usage: "dogfact/pupfact" }; diff --git a/src/events/disconnect.js b/src/events/disconnect.js new file mode 100644 index 0000000..932b5fd --- /dev/null +++ b/src/events/disconnect.js @@ -0,0 +1,3 @@ +module.exports = client => { // logs if the bot gets disconnected from discord. + client.logger.warn(`Bot disconnected at ${new Date()}`); +}; \ No newline at end of file diff --git a/src/events/reconnection.js b/src/events/reconnection.js new file mode 100644 index 0000000..d0a6fb2 --- /dev/null +++ b/src/events/reconnection.js @@ -0,0 +1,3 @@ +module.exports = client => { // logs when the bot reconnects to discord + client.logger.info(`Reconnecting at ${new Date()}`); +}; \ No newline at end of file From f032e0c1e9d1be82a263460603a6a6c4959f0c80 Mon Sep 17 00:00:00 2001 From: Terryiscool160 <48654513+Terryiscool160@users.noreply.github.com> Date: Tue, 10 Mar 2020 00:18:05 +0000 Subject: [PATCH 08/37] More stuff. Added a dice roll command. --- README.md | 8 ++++---- src/commands/diceroll.js | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 src/commands/diceroll.js diff --git a/README.md b/README.md index 693f553..c95b417 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Woomy -Woomy is a all-purpose discord bot built off the [guidebot](https://github.com/AnIdiotsGuide/guidebot) base and coded in node.js using discord.js. +Woomy is a all-purpose discord bot built off the [guidebot](https://github.com/AnIdiotsGuide/guidebot) base and coded in node.js using discord.js. # How to use The easiest way to use Woomy is to invite it to your server with [this link.](https://discordapp.com/oauth2/authorize?client_id=435961704145485835&permissions=2134240503&scope=bot) It is hosted 24/7 and automatically updates itself when a new release is made available, making sure you always get the newest features. -Self hosting is generally not recommended, but instructions are provided below if you still wish to do so. Woomy's code will need to be modified before it will run on your machine. +You can also self-host! Some modificatiomns to the code will need to be made before Woomy will run on your machine, but anyone who can read errors will figure out what needs to be changed pretty quickly :P # Requirements - git - node.js v12.0.0 or higher - node-gyp build tools -- ffmpeg +- ffmpeg (or ffmpeg-static) # Installation - Clone Woomy to your machine @@ -18,4 +18,4 @@ Self hosting is generally not recommended, but instructions are provided below i - Open config.js in your code editor and insert all the required information # Contributing -If you wish to contribute to Woomy, please fork the repository and open a pull request. +If you wish to contribute to Woomy, please fork the repository and open a pull request. Any contribution is appreciated <3 \ No newline at end of file diff --git a/src/commands/diceroll.js b/src/commands/diceroll.js new file mode 100644 index 0000000..569f381 --- /dev/null +++ b/src/commands/diceroll.js @@ -0,0 +1,27 @@ +exports.run = async (bot, message, args) => { + if (args.length === 0) { + message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + } else { + if (args[0].match(/^\d+$/)) { + message.channel.send(`🎲 The dice landed on ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}.`); + } else { + message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + } + } + }; + + exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["diceroll"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "dice", + category: "Fun", + description: "Rolls a dice.", + usage: "dice" + }; + \ No newline at end of file From 0c377f6cce942925a45398d379259c3efce0d4ef Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 00:35:38 +0000 Subject: [PATCH 09/37] Update dicerole.js --- src/commands/dicerole.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/dicerole.js b/src/commands/dicerole.js index 569f381..b307d4e 100644 --- a/src/commands/dicerole.js +++ b/src/commands/dicerole.js @@ -1,11 +1,11 @@ exports.run = async (bot, message, args) => { if (args.length === 0) { - message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); } else { if (args[0].match(/^\d+$/)) { - message.channel.send(`🎲 The dice landed on ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}.`); + message.channel.send(`🎲 You rolled a ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}!`); } else { - message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); } } }; @@ -24,4 +24,4 @@ exports.run = async (bot, message, args) => { description: "Rolls a dice.", usage: "dice" }; - \ No newline at end of file + From 3fa96ca6f81dfad299d0ca1f8456109d83296fe6 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 00:41:59 +0000 Subject: [PATCH 10/37] Delete dicerole.js --- src/commands/dicerole.js | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/commands/dicerole.js diff --git a/src/commands/dicerole.js b/src/commands/dicerole.js deleted file mode 100644 index b307d4e..0000000 --- a/src/commands/dicerole.js +++ /dev/null @@ -1,27 +0,0 @@ -exports.run = async (bot, message, args) => { - if (args.length === 0) { - message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); - } else { - if (args[0].match(/^\d+$/)) { - message.channel.send(`🎲 You rolled a ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}!`); - } else { - message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); - } - } - }; - - exports.conf = { - enabled: true, - guildOnly: false, - aliases: ["diceroll"], - permLevel: "User", - requiredPerms: [] - }; - - exports.help = { - name: "dice", - category: "Fun", - description: "Rolls a dice.", - usage: "dice" - }; - From 76d6230e97777e6b00dc33ba2e8ea6da957bc1a0 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 00:42:20 +0000 Subject: [PATCH 11/37] Update diceroll.js --- src/commands/diceroll.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/diceroll.js b/src/commands/diceroll.js index 569f381..b307d4e 100644 --- a/src/commands/diceroll.js +++ b/src/commands/diceroll.js @@ -1,11 +1,11 @@ exports.run = async (bot, message, args) => { if (args.length === 0) { - message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); } else { if (args[0].match(/^\d+$/)) { - message.channel.send(`🎲 The dice landed on ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}.`); + message.channel.send(`🎲 You rolled a ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}!`); } else { - message.channel.send(`🎲 The dice landed on ${Array.from(Array(6).keys()).random() + 1}.`); + message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); } } }; @@ -24,4 +24,4 @@ exports.run = async (bot, message, args) => { description: "Rolls a dice.", usage: "dice" }; - \ No newline at end of file + From c4ca29f56de773b047083d3ca51d0f003de416b9 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 11:46:27 +1100 Subject: [PATCH 12/37] Update changes.txt --- changes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changes.txt b/changes.txt index daa5b88..25e245c 100644 --- a/changes.txt +++ b/changes.txt @@ -1,2 +1,6 @@ Links to avatars now lead to the original file size Bots now get a bot badge in the userinfo command +Added dogfact and catfact command (terry) +index.js now has better logging of when things fail to load/initialize (terry) +added `dice`, rolls a 6 sided die (terry) +Added two new events, disconnect.js and reconnection.js. Should log when the bot loses connection/reconnects to discord (terry) \ No newline at end of file From b9b14a45d2662911b449e22200e4fc1c2dd04e07 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 12:01:44 +1100 Subject: [PATCH 13/37] Delete disconnect.js, reconnection.js --- src/events/disconnect.js | 3 --- src/events/reconnection.js | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 src/events/disconnect.js delete mode 100644 src/events/reconnection.js diff --git a/src/events/disconnect.js b/src/events/disconnect.js deleted file mode 100644 index 932b5fd..0000000 --- a/src/events/disconnect.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = client => { // logs if the bot gets disconnected from discord. - client.logger.warn(`Bot disconnected at ${new Date()}`); -}; \ No newline at end of file diff --git a/src/events/reconnection.js b/src/events/reconnection.js deleted file mode 100644 index d0a6fb2..0000000 --- a/src/events/reconnection.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = client => { // logs when the bot reconnects to discord - client.logger.info(`Reconnecting at ${new Date()}`); -}; \ No newline at end of file From b62f5aeef1c5e0b3853c1c7239aa1a0119f13059 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 12:20:28 +1100 Subject: [PATCH 14/37] help is now cooler n stuff --- changes.txt | 2 +- src/commands/help.js | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/changes.txt b/changes.txt index 25e245c..e3ed03b 100644 --- a/changes.txt +++ b/changes.txt @@ -3,4 +3,4 @@ Bots now get a bot badge in the userinfo command Added dogfact and catfact command (terry) index.js now has better logging of when things fail to load/initialize (terry) added `dice`, rolls a 6 sided die (terry) -Added two new events, disconnect.js and reconnection.js. Should log when the bot loses connection/reconnects to discord (terry) \ No newline at end of file +Help command changed, the amount of commands in each category and overall is now displayed \ No newline at end of file diff --git a/src/commands/help.js b/src/commands/help.js index 9ccb578..c9744a2 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -4,6 +4,7 @@ exports.run = (client, message, args, level) => { var ran = false; var output = ""; + var commands = 0; var prefix; var currentCategory; @@ -14,7 +15,7 @@ exports.run = (client, message, args, level) => { }; if(!args[0]) { - embed.setTitle("Command list"); + embed.setTitle(`Commands [${client.commands.size}]`); embed.setDescription(`⁣For more information on a specific command use \`${prefix}help \`\nFor the full command list use \`${prefix}help all\`\n`); const myCommands = message.guild ? client.commands.filter( @@ -37,16 +38,18 @@ exports.run = (client, message, args, level) => { const cat = c.help.category.toProperCase(); if (currentCategory !== cat) { if(ran == true) { - embed.addField(currentCategory + ":", output.slice(0, -6)) + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)) output = ""; + commands = 0; } currentCategory = cat; ran = true } - output += `\`${prefix}${c.help.name}\`**,** `; + output += `\`${prefix}${c.help.name}\`, `; + commands = commands + 1; }); - embed.addField(currentCategory + ":", output.slice(0, -6)); + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)); embed.addField( "Invite me", @@ -84,16 +87,18 @@ exports.run = (client, message, args, level) => { const cat = c.help.category.toProperCase(); if (currentCategory !== cat) { if(ran == true) { - embed.addField(currentCategory + ":", output.slice(0, -6)) + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)) output = ""; + commands = 0; } currentCategory = cat; ran = true } - output += `\`${prefix}${c.help.name}\`**,** `; + output += `\`${prefix}${c.help.name}\`, `; + commands = commands + 1; }); - embed.addField(currentCategory + ":", output.slice(0, -6)); + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)); embed.addField( "Invite me", From 155eac0688414124b8c875d93966eb5c08f174d3 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 12:38:42 +1100 Subject: [PATCH 15/37] Update version.json --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index b6a4488..3e289f1 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "number": "1.1.0", + "number": "1.2.0", "changelog": "**1.1.0 CHANGELOG:**\n> • Added `~softban`, bans and unbans a user to clear messages\n> • Added `~emoji`, enlarges custom emojis\n> • Added `~inspirobot`, generates an inspirational quote\n> • `~serverinfo` has been changed to be more consistent, and also now displays boosts and if the server is partnered and stuff\n> • `~userinfo` has been changed to be more consistent, also added some stuff\n> • `~about` has been changed, added a thumbnail and removed the description\n> • `~colour` has been changed, it can now generate colours from text\n> • `~hackban` no longer has its own embed\n> • `~eval` now logs to hastebin if output is too large\n> • role names are no longer case sensitive\n> • `~echo` renamed `~say`\n> • Users with the ADMINISTRATOR permission now automatically recieve woomy admin\n> • Fixed `~flip`, `~purge`, `~bohemian_rhapsody` and `~creeper`\n> • Guild join/leave messages no longer include the guild name\n> • Some emojis have been changed\n> • Woomy now supports discord.js v12\n> • Files have been restructured\n> • Logger now logs error stack\n> • Restart now exits with code 0" } From b11f18b1a98ba94c0211cef10129a9acbdcda8c1 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Tue, 10 Mar 2020 20:35:16 +1100 Subject: [PATCH 16/37] Update index.js --- index.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 6adb8b7..4e535ee 100644 --- a/index.js +++ b/index.js @@ -9,35 +9,35 @@ const client = new Discord.Client(); try { client.config = require('./config'); } catch (err) { - console.log('Could not load config.js. \n', err); + console.log('Could not load config.js: \n', err); process.exit(); } try{ client.version = require('./version.json'); } catch (err) { - console.log('Could not load version.json. \n', err); + console.log('Could not load version.json: \n', err); process.exit(); } try{ client.logger = require('./src/modules/Logger'); } catch (err) { - console.log('Could not load Logger.js. \n', err); + console.log('Could not load Logger.js: \n', err); process.exit(); } try{ require("./src/modules/functions")(client); } catch (err) { - console.log('Could not load functions.js. \n', err); + console.log('Could not load functions.js: \n', err); process.exit(); } try{ client.logger.setClient(client); } catch (err) { - console.log('Logger failed to initialize. \n', err); + console.log('Logger failed to initialize: \n', err); process.exit(1); } @@ -45,34 +45,36 @@ if(process.env['USER'] != 'container') { client.devmode = true; } else { client.devmode = false; - const dblapi = new DBL(client.config.dblkey, client); + if(client.config.dblkey.length == 0) { + const dblapi = new DBL(client.config.dblkey, client); + } } try{ client.commands = new Enmap(); } catch (err) { - console.log('Failed to create the commands map. \n', err); + console.log('Failed to create the commands database: \n', err); process.exit(); } try{ client.aliases = new Enmap(); } catch (err) { - console.log('Failed to create the aliases map. \n', err); + console.log('Failed to create the aliases database: \n', err); process.exit(); } try{ client.settings = new Enmap({name: 'settings'}); } catch (err) { - console.log('Failed to initialize the settings database. \n', err); + console.log('Failed to initialize the settings database: \n', err); process.exit(); } try{ client.blacklist = new Enmap({name: 'blacklist'}); } catch (err) { - console.log('Failed to initialize the blacklist database. \n', err); + console.log('Failed to initialize the blacklist database: \n', err); process.exit(1); } @@ -108,7 +110,7 @@ const init = async () => { client.levelCache[thisLevel.name] = thisLevel.level; }; } catch (err) { - console.log('Level cache failed to initialize. \n', err); + console.log('Level cache failed to initialize: \n', err); process.exit(); } @@ -119,12 +121,12 @@ const init = async () => { client.login(client.config.token); }; } catch (err) { - console.log('Unable to login to Discord. \n', err); + console.log('Could not login to Discord: \n', err); process.exit(1); } }; init(); } catch (err) { - console.log('Initialization failed. \n', err); + console.log('Initialization failed: \n', err); process.exit(1); } From 1e66c75982c9efc2538157f1c5bb905e6acc989b Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Wed, 11 Mar 2020 13:09:40 +1100 Subject: [PATCH 17/37] Update help.js --- src/commands/help.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/help.js b/src/commands/help.js index c9744a2..beeda6d 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -68,7 +68,7 @@ exports.run = (client, message, args, level) => { }; if(args[0].toLowerCase() == "all") { - embed.setTitle("Command list"); + embed.setTitle(`Commands [${client.commands.size}]`); embed.setDescription(`⁣For more information on a specific command use \`${prefix}help \`\nFor the full command list use \`${prefix}help all\`\n`); const myCommands = client.commands From 42f3fd10ff0072c6834f7d7744f720210d6aaa0d Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Wed, 11 Mar 2020 14:33:03 +1100 Subject: [PATCH 18/37] why was this logging a unix timestamp --- src/commands/userinfo.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/commands/userinfo.js b/src/commands/userinfo.js index f84b40a..8d7008b 100644 --- a/src/commands/userinfo.js +++ b/src/commands/userinfo.js @@ -50,13 +50,6 @@ exports.run = (client, message, args) => { if(badges.length > 0) { badges += "\n" } - - createdTimestamp = user.user.createdTimestamp; - var date = new Date(createdTimestamp * 1000); - var hours = date.getHours(); - var minutes = "0" + date.getMinutes(); - var seconds = "o" + date.getSeconds(); - console.log(date) user.roles.cache.forEach((role) => { roles = roles + role.name + "`, `" From a82d6cff820f945e870bc2ab28791bacda8e4af7 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Wed, 11 Mar 2020 21:46:13 +1100 Subject: [PATCH 19/37] Synced changes --- changes.txt | 5 ++++- src/commands/inspirobot.js | 2 +- src/commands/ship.js | 37 +++++++++++++++++++++++++++++++++++++ src/modules/functions.js | 16 ++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/commands/ship.js diff --git a/changes.txt b/changes.txt index e3ed03b..20d4a91 100644 --- a/changes.txt +++ b/changes.txt @@ -3,4 +3,7 @@ Bots now get a bot badge in the userinfo command Added dogfact and catfact command (terry) index.js now has better logging of when things fail to load/initialize (terry) added `dice`, rolls a 6 sided die (terry) -Help command changed, the amount of commands in each category and overall is now displayed \ No newline at end of file +Help command changed, the amount of commands in each category and overall is now displayed +added `inspire` as an alias for inspirobot +ship command +added find by mention to functions \ No newline at end of file diff --git a/src/commands/inspirobot.js b/src/commands/inspirobot.js index 6a26ee7..5ba4e0a 100644 --- a/src/commands/inspirobot.js +++ b/src/commands/inspirobot.js @@ -20,7 +20,7 @@ exports.run = async (client, message) => { exports.conf = { enabled: true, guildOnly: false, - aliases: [], + aliases: ["inspire"], permLevel: "User", requiredPerms: [] }; diff --git a/src/commands/ship.js b/src/commands/ship.js new file mode 100644 index 0000000..cd187b9 --- /dev/null +++ b/src/commands/ship.js @@ -0,0 +1,37 @@ +const request = require('request') +exports.run = async (client, message, args) => { + message.channel.startTyping(); + + var user = client.getUserFromMention(args[0]) + var user2 = client.getUserFromMention(args[1]) + + var secondLength = Math.floor(user2.username.length / 2); + + var first = user.username.substr(0, user.username.length / 2) + var second = user2.username.substr(secondLength, user2.username.length / 2) + + try { + var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) + message.channel.send(`Your ship name is **${first+second}!**`, attachment) + message.channel.stopTyping(); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "ship", + category: "Fun", + description: "Ship two people together <3", + usage: "ship name name2" +}; + diff --git a/src/modules/functions.js b/src/modules/functions.js index 85ec48d..98cf223 100644 --- a/src/modules/functions.js +++ b/src/modules/functions.js @@ -133,6 +133,22 @@ module.exports = client => { return a; }; + // USER OBJECT FROM MENTION + client.getUserFromMention = mention => { + if (!mention) return; + + if (mention.startsWith('<@') && mention.endsWith('>')) { + mention = mention.slice(2, -1); + + if (mention.startsWith('!')) { + mention = mention.slice(1); + } + + return client.users.cache.get(mention); + } + } + + // MUSIC client.music = {guilds: {}}; From 5d8a81523f658d8fab2d8f1e8044cbb8d9e97831 Mon Sep 17 00:00:00 2001 From: MrTech999 <48654513+MrTech999@users.noreply.github.com> Date: Wed, 11 Mar 2020 20:47:06 +0000 Subject: [PATCH 20/37] Added yodish. --- changes.txt | 8 ++++++++ index.js | 28 +++++++++++++++------------- src/commands/catfact.js | 8 +++++++- src/commands/dogfact.js | 8 +++++++- src/commands/help.js | 21 +++++++++++++-------- src/commands/inspirobot.js | 2 +- src/commands/ship.js | 37 +++++++++++++++++++++++++++++++++++++ src/commands/userinfo.js | 7 ------- src/commands/yoda.js | 31 +++++++++++++++++++++++++++++++ src/modules/functions.js | 16 ++++++++++++++++ version.json | 2 +- 11 files changed, 136 insertions(+), 32 deletions(-) create mode 100644 src/commands/ship.js create mode 100644 src/commands/yoda.js diff --git a/changes.txt b/changes.txt index daa5b88..f7f1849 100644 --- a/changes.txt +++ b/changes.txt @@ -1,2 +1,10 @@ +Added a yodish command (terry) Links to avatars now lead to the original file size Bots now get a bot badge in the userinfo command +Added dogfact and catfact command (terry) +index.js now has better logging of when things fail to load/initialize (terry) +added `dice`, rolls a 6 sided die (terry) +Help command changed, the amount of commands in each category and overall is now displayed +added `inspire` as an alias for inspirobot +ship command +added find by mention to functions \ No newline at end of file diff --git a/index.js b/index.js index 6adb8b7..4e535ee 100644 --- a/index.js +++ b/index.js @@ -9,35 +9,35 @@ const client = new Discord.Client(); try { client.config = require('./config'); } catch (err) { - console.log('Could not load config.js. \n', err); + console.log('Could not load config.js: \n', err); process.exit(); } try{ client.version = require('./version.json'); } catch (err) { - console.log('Could not load version.json. \n', err); + console.log('Could not load version.json: \n', err); process.exit(); } try{ client.logger = require('./src/modules/Logger'); } catch (err) { - console.log('Could not load Logger.js. \n', err); + console.log('Could not load Logger.js: \n', err); process.exit(); } try{ require("./src/modules/functions")(client); } catch (err) { - console.log('Could not load functions.js. \n', err); + console.log('Could not load functions.js: \n', err); process.exit(); } try{ client.logger.setClient(client); } catch (err) { - console.log('Logger failed to initialize. \n', err); + console.log('Logger failed to initialize: \n', err); process.exit(1); } @@ -45,34 +45,36 @@ if(process.env['USER'] != 'container') { client.devmode = true; } else { client.devmode = false; - const dblapi = new DBL(client.config.dblkey, client); + if(client.config.dblkey.length == 0) { + const dblapi = new DBL(client.config.dblkey, client); + } } try{ client.commands = new Enmap(); } catch (err) { - console.log('Failed to create the commands map. \n', err); + console.log('Failed to create the commands database: \n', err); process.exit(); } try{ client.aliases = new Enmap(); } catch (err) { - console.log('Failed to create the aliases map. \n', err); + console.log('Failed to create the aliases database: \n', err); process.exit(); } try{ client.settings = new Enmap({name: 'settings'}); } catch (err) { - console.log('Failed to initialize the settings database. \n', err); + console.log('Failed to initialize the settings database: \n', err); process.exit(); } try{ client.blacklist = new Enmap({name: 'blacklist'}); } catch (err) { - console.log('Failed to initialize the blacklist database. \n', err); + console.log('Failed to initialize the blacklist database: \n', err); process.exit(1); } @@ -108,7 +110,7 @@ const init = async () => { client.levelCache[thisLevel.name] = thisLevel.level; }; } catch (err) { - console.log('Level cache failed to initialize. \n', err); + console.log('Level cache failed to initialize: \n', err); process.exit(); } @@ -119,12 +121,12 @@ const init = async () => { client.login(client.config.token); }; } catch (err) { - console.log('Unable to login to Discord. \n', err); + console.log('Could not login to Discord: \n', err); process.exit(1); } }; init(); } catch (err) { - console.log('Initialization failed. \n', err); + console.log('Initialization failed: \n', err); process.exit(1); } diff --git a/src/commands/catfact.js b/src/commands/catfact.js index 4944b43..8beb770 100644 --- a/src/commands/catfact.js +++ b/src/commands/catfact.js @@ -1,10 +1,16 @@ const request = require("request"); exports.run = async (bot, message, args) => { + message.channel.startTyping(); + try{ request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { - if (error) throw new Error(error); message.channel.send(`**Did you know?**\n ${body.data[0].fact}`); + message.channel.startTyping(); }); +} catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); +}; }; exports.conf = { diff --git a/src/commands/dogfact.js b/src/commands/dogfact.js index dc6bf7c..cd89858 100644 --- a/src/commands/dogfact.js +++ b/src/commands/dogfact.js @@ -1,10 +1,16 @@ const request = require("request"); exports.run = async (bot, message, args) => { + message.channel.startTyping(); + try{ request({ uri: "https://dog-api.kinduff.com/api/facts", json: true }, (error, response, body) => { - if (error) throw new Error(error); + message.channel.stopTyping(); message.channel.send(`**Did you know?**\n ${body.facts[0]}`); }); +} catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); +}; }; exports.conf = { diff --git a/src/commands/help.js b/src/commands/help.js index 9ccb578..beeda6d 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -4,6 +4,7 @@ exports.run = (client, message, args, level) => { var ran = false; var output = ""; + var commands = 0; var prefix; var currentCategory; @@ -14,7 +15,7 @@ exports.run = (client, message, args, level) => { }; if(!args[0]) { - embed.setTitle("Command list"); + embed.setTitle(`Commands [${client.commands.size}]`); embed.setDescription(`⁣For more information on a specific command use \`${prefix}help \`\nFor the full command list use \`${prefix}help all\`\n`); const myCommands = message.guild ? client.commands.filter( @@ -37,16 +38,18 @@ exports.run = (client, message, args, level) => { const cat = c.help.category.toProperCase(); if (currentCategory !== cat) { if(ran == true) { - embed.addField(currentCategory + ":", output.slice(0, -6)) + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)) output = ""; + commands = 0; } currentCategory = cat; ran = true } - output += `\`${prefix}${c.help.name}\`**,** `; + output += `\`${prefix}${c.help.name}\`, `; + commands = commands + 1; }); - embed.addField(currentCategory + ":", output.slice(0, -6)); + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)); embed.addField( "Invite me", @@ -65,7 +68,7 @@ exports.run = (client, message, args, level) => { }; if(args[0].toLowerCase() == "all") { - embed.setTitle("Command list"); + embed.setTitle(`Commands [${client.commands.size}]`); embed.setDescription(`⁣For more information on a specific command use \`${prefix}help \`\nFor the full command list use \`${prefix}help all\`\n`); const myCommands = client.commands @@ -84,16 +87,18 @@ exports.run = (client, message, args, level) => { const cat = c.help.category.toProperCase(); if (currentCategory !== cat) { if(ran == true) { - embed.addField(currentCategory + ":", output.slice(0, -6)) + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)) output = ""; + commands = 0; } currentCategory = cat; ran = true } - output += `\`${prefix}${c.help.name}\`**,** `; + output += `\`${prefix}${c.help.name}\`, `; + commands = commands + 1; }); - embed.addField(currentCategory + ":", output.slice(0, -6)); + embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)); embed.addField( "Invite me", diff --git a/src/commands/inspirobot.js b/src/commands/inspirobot.js index 6a26ee7..5ba4e0a 100644 --- a/src/commands/inspirobot.js +++ b/src/commands/inspirobot.js @@ -20,7 +20,7 @@ exports.run = async (client, message) => { exports.conf = { enabled: true, guildOnly: false, - aliases: [], + aliases: ["inspire"], permLevel: "User", requiredPerms: [] }; diff --git a/src/commands/ship.js b/src/commands/ship.js new file mode 100644 index 0000000..cd187b9 --- /dev/null +++ b/src/commands/ship.js @@ -0,0 +1,37 @@ +const request = require('request') +exports.run = async (client, message, args) => { + message.channel.startTyping(); + + var user = client.getUserFromMention(args[0]) + var user2 = client.getUserFromMention(args[1]) + + var secondLength = Math.floor(user2.username.length / 2); + + var first = user.username.substr(0, user.username.length / 2) + var second = user2.username.substr(secondLength, user2.username.length / 2) + + try { + var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) + message.channel.send(`Your ship name is **${first+second}!**`, attachment) + message.channel.stopTyping(); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "ship", + category: "Fun", + description: "Ship two people together <3", + usage: "ship name name2" +}; + diff --git a/src/commands/userinfo.js b/src/commands/userinfo.js index f84b40a..8d7008b 100644 --- a/src/commands/userinfo.js +++ b/src/commands/userinfo.js @@ -50,13 +50,6 @@ exports.run = (client, message, args) => { if(badges.length > 0) { badges += "\n" } - - createdTimestamp = user.user.createdTimestamp; - var date = new Date(createdTimestamp * 1000); - var hours = date.getHours(); - var minutes = "0" + date.getMinutes(); - var seconds = "o" + date.getSeconds(); - console.log(date) user.roles.cache.forEach((role) => { roles = roles + role.name + "`, `" diff --git a/src/commands/yoda.js b/src/commands/yoda.js new file mode 100644 index 0000000..aae6af0 --- /dev/null +++ b/src/commands/yoda.js @@ -0,0 +1,31 @@ +const request = require('request') +exports.run = async (client, message, args) => { + const speech = args.join(' '); + if (!args[0]) { + return message.channel.send(`<:error:466995152976871434> Please include text for me to convert to yodish. Yes.`) + } + try { + const { text } = request({ uri: `http://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(speech.toLowerCase())}`, json: true }, (error, response, body) => { + message.channel.send(JSON.parse(text).yodish) + }); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + } + +} + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["yoda","yodasay"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "yodish", + category: "Fun", + description: "Turns any text you input into yodish. Yes.", + usage: "yodish " + }; \ No newline at end of file diff --git a/src/modules/functions.js b/src/modules/functions.js index 85ec48d..98cf223 100644 --- a/src/modules/functions.js +++ b/src/modules/functions.js @@ -133,6 +133,22 @@ module.exports = client => { return a; }; + // USER OBJECT FROM MENTION + client.getUserFromMention = mention => { + if (!mention) return; + + if (mention.startsWith('<@') && mention.endsWith('>')) { + mention = mention.slice(2, -1); + + if (mention.startsWith('!')) { + mention = mention.slice(1); + } + + return client.users.cache.get(mention); + } + } + + // MUSIC client.music = {guilds: {}}; diff --git a/version.json b/version.json index b6a4488..3e289f1 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "number": "1.1.0", + "number": "1.2.0", "changelog": "**1.1.0 CHANGELOG:**\n> • Added `~softban`, bans and unbans a user to clear messages\n> • Added `~emoji`, enlarges custom emojis\n> • Added `~inspirobot`, generates an inspirational quote\n> • `~serverinfo` has been changed to be more consistent, and also now displays boosts and if the server is partnered and stuff\n> • `~userinfo` has been changed to be more consistent, also added some stuff\n> • `~about` has been changed, added a thumbnail and removed the description\n> • `~colour` has been changed, it can now generate colours from text\n> • `~hackban` no longer has its own embed\n> • `~eval` now logs to hastebin if output is too large\n> • role names are no longer case sensitive\n> • `~echo` renamed `~say`\n> • Users with the ADMINISTRATOR permission now automatically recieve woomy admin\n> • Fixed `~flip`, `~purge`, `~bohemian_rhapsody` and `~creeper`\n> • Guild join/leave messages no longer include the guild name\n> • Some emojis have been changed\n> • Woomy now supports discord.js v12\n> • Files have been restructured\n> • Logger now logs error stack\n> • Restart now exits with code 0" } From cab212cecc136c206097020a93fe88e870a6e1b4 Mon Sep 17 00:00:00 2001 From: Terryiscool160 <48654513+Terryiscool160@users.noreply.github.com> Date: Wed, 11 Mar 2020 20:52:43 +0000 Subject: [PATCH 21/37] Add files via upload --- changes.txt | 8 ++++++++ src/commands/catfact.js | 8 +++++++- src/commands/dogfact.js | 8 +++++++- src/commands/yoda.js | 31 +++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/commands/yoda.js diff --git a/changes.txt b/changes.txt index daa5b88..e91c096 100644 --- a/changes.txt +++ b/changes.txt @@ -1,2 +1,10 @@ +Added a yodish command and made catfact and dogfact say if the api errors (terry) Links to avatars now lead to the original file size Bots now get a bot badge in the userinfo command +Added dogfact and catfact command (terry) +index.js now has better logging of when things fail to load/initialize (terry) +added `dice`, rolls a 6 sided die (terry) +Help command changed, the amount of commands in each category and overall is now displayed +added `inspire` as an alias for inspirobot +ship command +added find by mention to functions \ No newline at end of file diff --git a/src/commands/catfact.js b/src/commands/catfact.js index 4944b43..8beb770 100644 --- a/src/commands/catfact.js +++ b/src/commands/catfact.js @@ -1,10 +1,16 @@ const request = require("request"); exports.run = async (bot, message, args) => { + message.channel.startTyping(); + try{ request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { - if (error) throw new Error(error); message.channel.send(`**Did you know?**\n ${body.data[0].fact}`); + message.channel.startTyping(); }); +} catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); +}; }; exports.conf = { diff --git a/src/commands/dogfact.js b/src/commands/dogfact.js index dc6bf7c..cd89858 100644 --- a/src/commands/dogfact.js +++ b/src/commands/dogfact.js @@ -1,10 +1,16 @@ const request = require("request"); exports.run = async (bot, message, args) => { + message.channel.startTyping(); + try{ request({ uri: "https://dog-api.kinduff.com/api/facts", json: true }, (error, response, body) => { - if (error) throw new Error(error); + message.channel.stopTyping(); message.channel.send(`**Did you know?**\n ${body.facts[0]}`); }); +} catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); +}; }; exports.conf = { diff --git a/src/commands/yoda.js b/src/commands/yoda.js new file mode 100644 index 0000000..2d1645d --- /dev/null +++ b/src/commands/yoda.js @@ -0,0 +1,31 @@ +const request = require('request') +exports.run = async (client, message, args) => { + const speech = args.join(' '); + if (!args[0]) { + return message.channel.send(`<:error:466995152976871434> Please include text for me to convert to yodish. Yes.`) + } + try { + const { text } = request({ uri: `http://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(speech.toLowerCase())}`, json: true }, (error, response, body) => { + message.channel.send(JSON.parse(text).yodish) + }); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + } + +} + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["yoda","yodasay"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "yodish", + category: "Fun", + description: "Turns any text you input into yodish. Yes.", + usage: "yodish " + }; \ No newline at end of file From cc02ccf89d584ff5328222a66407594c99fd742a Mon Sep 17 00:00:00 2001 From: MrTech999 <48654513+MrTech999@users.noreply.github.com> Date: Wed, 11 Mar 2020 20:52:55 +0000 Subject: [PATCH 22/37] Update changes.txt --- changes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index f7f1849..e91c096 100644 --- a/changes.txt +++ b/changes.txt @@ -1,4 +1,4 @@ -Added a yodish command (terry) +Added a yodish command and made catfact and dogfact say if the api errors (terry) Links to avatars now lead to the original file size Bots now get a bot badge in the userinfo command Added dogfact and catfact command (terry) From 9948976cf7faacf6fe5a167ff880a35b9aef6313 Mon Sep 17 00:00:00 2001 From: MrTech999 <48654513+MrTech999@users.noreply.github.com> Date: Wed, 11 Mar 2020 20:58:58 +0000 Subject: [PATCH 23/37] Update dogfact.js --- src/commands/dogfact.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/dogfact.js b/src/commands/dogfact.js index cd89858..31d1639 100644 --- a/src/commands/dogfact.js +++ b/src/commands/dogfact.js @@ -4,8 +4,8 @@ exports.run = async (bot, message, args) => { message.channel.startTyping(); try{ request({ uri: "https://dog-api.kinduff.com/api/facts", json: true }, (error, response, body) => { - message.channel.stopTyping(); message.channel.send(`**Did you know?**\n ${body.facts[0]}`); + message.channel.stopTyping(); }); } catch(err) { message.channel.send(`<:error:466995152976871434> API error: ${err}`); From 652b03136e70d74387817755758d26ac7f2d1a19 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Mon, 16 Mar 2020 12:14:33 +1100 Subject: [PATCH 24/37] synced changes --- package.json | 4 +- resources/other/coolpeople.json | 19 ++++++++++ src/commands/catfact.js | 16 ++++---- src/commands/colourify.js | 53 +++++++++++++++++++++++++++ src/commands/ship.js | 41 +++++++++++++++++++-- src/commands/ship1.js | 65 +++++++++++++++++++++++++++++++++ src/commands/userinfo.js | 14 ++++++- src/commands/yoda.js | 28 +++++++------- src/modules/functions.js | 2 +- 9 files changed, 215 insertions(+), 27 deletions(-) create mode 100644 resources/other/coolpeople.json create mode 100644 src/commands/colourify.js create mode 100644 src/commands/ship1.js diff --git a/package.json b/package.json index 7210610..1c03415 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Woomy is a all-purpose discord bot built off the guidebot base and coded in node.js using discord.js.", "main": "index.js", "dependencies": { + "@discordjs/opus": "^0.1.0", "better-sqlite3": "^5.4.1", "chalk": "^3.0.0", "dblapi.js": "^2.3.1", @@ -12,12 +13,13 @@ "garfield": "^1.1.2", "get-youtube-id": "^1.0.1", "hastebin-gen": "^2.0.5", + "is-url": "^1.2.4", "moment": "^2.24.0", "moment-duration-format": "^2.3.2", "prism-media": "^1.2.1", "randomcolor": "^0.5.4", - "request": "^2.88.2", "relevant-urban": "^2.0.0", + "request": "^2.88.2", "urban": "^0.3.2", "url-unshort": "^5.0.0", "url-unshorten": "^1.0.6", diff --git a/resources/other/coolpeople.json b/resources/other/coolpeople.json new file mode 100644 index 0000000..f0de195 --- /dev/null +++ b/resources/other/coolpeople.json @@ -0,0 +1,19 @@ +{ + "coolPeople": [ + "448354605617643520", + "433790467830972417", + "231777839576252417", + "285992938314661899", + "231704701433937931", + "324937993972350976", + "336492042299637771", + "273867501006225419", + "331870539897372672", + "304000458144481280", + "239787232666451980", + "264970229514371072", + "254310746450690048", + "358390849807319040", + "211011138656272386" + ] +} \ No newline at end of file diff --git a/src/commands/catfact.js b/src/commands/catfact.js index 8beb770..9fef875 100644 --- a/src/commands/catfact.js +++ b/src/commands/catfact.js @@ -3,14 +3,14 @@ const request = require("request"); exports.run = async (bot, message, args) => { message.channel.startTyping(); try{ - request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { - message.channel.send(`**Did you know?**\n ${body.data[0].fact}`); - message.channel.startTyping(); - }); -} catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); - message.channel.stopTyping(); -}; + request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { + message.channel.send(`**Did you know?**\n ${body.data[0].fact}`); + message.channel.stopTyping(); + }); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + }; }; exports.conf = { diff --git a/src/commands/colourify.js b/src/commands/colourify.js new file mode 100644 index 0000000..f13720d --- /dev/null +++ b/src/commands/colourify.js @@ -0,0 +1,53 @@ +const isURL = require("is-url") +exports.run = async (client, message, args) => { + var img; + if(!args[0]) { + if(!message.attachments.first()) { + return message.channel.send("No attachment") + }; + img = message.attachments.first().attachment; + } else { + if(isURL(args[0]) == true ) { + img = args[0]; + } else { + user = message.mentions.members.first(); + + if (!user) { + let users; + users = client.searchForMembers(message.guild, args[0]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0]; + }; + + if(user) { + img = user.user.avatarURL({format: "png", dynamic: true}) + } + } + }; + + var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/filter/magik?image=${img}`) + message.channel.send(attachment) +}; + + exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "magikt", + category: "Fun", + description: "Colourifies an image", + usage: "colourify user hex1 hex2" + }; + \ No newline at end of file diff --git a/src/commands/ship.js b/src/commands/ship.js index cd187b9..2ef0477 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -1,14 +1,49 @@ const request = require('request') exports.run = async (client, message, args) => { + + + //NOT FINISHED + + if(!args[0] || !args[1]) { + return message.channel.send(`<:error:466995152976871434> Please include two users`) + } message.channel.startTyping(); var user = client.getUserFromMention(args[0]) var user2 = client.getUserFromMention(args[1]) + + if (!user) { + let users; + users = client.searchForMembers(message.guild, args[0]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0]; + }; + + if (!user2) { + let users; + users = client.searchForMembers(message.guild, args[0]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user2 = users[0]; + }; var secondLength = Math.floor(user2.username.length / 2); - var first = user.username.substr(0, user.username.length / 2) - var second = user2.username.substr(secondLength, user2.username.length / 2) + var first = user.username.slice(0, user.username.length / 2) + var second = user2.username.slice(secondLength, user2.username.length / 2) try { var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) @@ -22,7 +57,7 @@ exports.run = async (client, message, args) => { exports.conf = { enabled: true, - guildOnly: false, + guildOnly: true, aliases: [], permLevel: "User", requiredPerms: [] diff --git a/src/commands/ship1.js b/src/commands/ship1.js new file mode 100644 index 0000000..ca96edd --- /dev/null +++ b/src/commands/ship1.js @@ -0,0 +1,65 @@ +const request = require('request') +exports.run = async (client, message, args) => { + + + //NOT FINISHED + + if(!args[0] || !args[1]) { + return message.channel.send(`<:error:466995152976871434> Please include two to five users`) + } + message.channel.startTyping(); + + var user = client.getUserFromMention(args[0]) + var user2 = client.getUserFromMention(args[1]) + + if (!user) { + let users; + users = client.searchForMembers(message.guild, args[0]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0]; + }; + + if (!user2) { + let users; + users = client.searchForMembers(message.guild, args[0]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user2 = users[0]; + }; + + var secondLength = Math.floor(user2.username.length / 2); + + var first = user.username.slice(0, user.username.length / 2) + var second = user2.username.slice(secondLength, user2.username.length / 2) + + message.channel.send(`Your ship name is **${shipname}!**`) +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "ship1", + category: "Fun", + description: "Ship two people together <3", + usage: "ship name name2" +}; + diff --git a/src/commands/userinfo.js b/src/commands/userinfo.js index 8d7008b..ddec46f 100644 --- a/src/commands/userinfo.js +++ b/src/commands/userinfo.js @@ -1,5 +1,5 @@ const Discord = require("discord.js"); - +const coolPeople = require('../../resources/other/coolpeople.json') exports.run = (client, message, args) => { var user; var guild; @@ -13,6 +13,8 @@ exports.run = (client, message, args) => { var tag; var id; var bot; + var coolPerson = false; + var friendos = coolPeople.coolPeople; if(message.guild) { user = message.mentions.members.first(); @@ -39,6 +41,15 @@ exports.run = (client, message, args) => { nick = `\n• **Nickname:** ${user.nickname}`; }; + for (var i = 0; i < friendos.length; i++) { + if (user.user.id == friendos[i]) + coolPerson = true; + }; + + if(coolPerson == true) { + badges += "🌟" + } + if(user.user.id == message.guild.ownerID) { badges += "<:owner:685703193694306331>" } @@ -46,6 +57,7 @@ exports.run = (client, message, args) => { if(user.user.bot) { badges += "<:bot:686489601678114859>" } + if(badges.length > 0) { badges += "\n" diff --git a/src/commands/yoda.js b/src/commands/yoda.js index 293d786..8b61784 100644 --- a/src/commands/yoda.js +++ b/src/commands/yoda.js @@ -1,20 +1,22 @@ const request = require('request') exports.run = async (client, message, args) => { - const speech = args.join(' '); - if (!args[0]) { - return message.channel.send(`<:error:466995152976871434> Please include text for me to convert to yodish. Yes.`) - } - try { - const { text } = request({ uri: `http://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(speech.toLowerCase())}`, json: true }, (error, response, body) => { - message.channel.send(JSON.parse(text).yodish) - }); - } catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); - message.channel.stopTyping(); - } + const speech = args.join(' '); + if (!speech) { + return message.channel.send(`<:error:466995152976871434> Please include text for me to convert to yodish. Yes.`) + }; -} + message.channel.startTyping(); + try{ + request({ uri: `http://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(speech.toLowerCase())}`, json: true }, (error, response, body) => { + message.channel.send(body.yodish); + message.channel.stopTyping(); + }); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + }; +}; exports.conf = { enabled: true, diff --git a/src/modules/functions.js b/src/modules/functions.js index 98cf223..bd30579 100644 --- a/src/modules/functions.js +++ b/src/modules/functions.js @@ -368,6 +368,6 @@ module.exports = client => { }); process.on("unhandledRejection", err => { - client.logger.error(`Unhandled rejection: ${err.stack}`); + client.logger.error(`Unhandled rejection: ${err}`); }); }; From a411fb3af49c9c5c2d02a9bf23844c299223bc18 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Mon, 16 Mar 2020 16:30:43 +1100 Subject: [PATCH 25/37] Update about.js --- src/commands/about.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/about.js b/src/commands/about.js index 5c1538f..ad1666b 100644 --- a/src/commands/about.js +++ b/src/commands/about.js @@ -45,7 +45,7 @@ exports.run = (client, message) => { exports.conf = { enabled: true, guildOnly: false, - aliases: ["stats"], + aliases: ["stats", "botinfo"], permLevel: "User", requiredPerms: [] }; From e5aad749f5be27ce7d515a2474b7b819a75516ac Mon Sep 17 00:00:00 2001 From: FLGX Date: Thu, 19 Mar 2020 10:46:53 +0100 Subject: [PATCH 26/37] make weather command return if an error occured --- src/commands/weather.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/weather.js b/src/commands/weather.js index f5fc362..4af8b86 100644 --- a/src/commands/weather.js +++ b/src/commands/weather.js @@ -13,7 +13,7 @@ exports.run = async (client, message, args, error) => { message.channel.startTyping(); weather.find({search: args.join(" "), degreeType: 'C'}, function(err, result) { - if(err) client.logger.log(`weather.js error: ${JSON.stringify(error)}`, "error") + if(err) return client.logger.log(`weather.js error: ${JSON.stringify(error)}`, "error") if(result.length < 2 || !result) { message.channel.stopTyping(); return message.channel.send("<:error:466995152976871434> City not found!"); From ea52ce2fcf77d92ca6e85f308876f86a27839262 Mon Sep 17 00:00:00 2001 From: FLGX Date: Thu, 19 Mar 2020 11:20:18 +0100 Subject: [PATCH 27/37] woomy mention prefix support --- src/events/message.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/events/message.js b/src/events/message.js index 3505c1c..f91dd7e 100644 --- a/src/events/message.js +++ b/src/events/message.js @@ -131,12 +131,20 @@ module.exports = async (client, message) => { }; }; - const prefixMention = new RegExp(`^<@!?${client.user.id}>( |)$`); + //const prefixMention = new RegExp(`^<@!?${client.user.id}>( |)$`); + const myMention = `<@&${client.user.id}>`; + const myMention2 = `<@!${client.user.id}>`; - if (message.content.match(prefixMention)) { - return message.channel.send(`Current prefix: \`${prefix}\``); - } + console.log(message.content); + if (message.content.startsWith(myMention) || message.content.startsWith(myMention2)) { + if(message.content.length > myMention.length + 1 && (message.content.substr(0, myMention.length + 1) == myMention + ' ' || message.content.substr(0, myMention2.length + 1) == myMention2 + ' ')) { + prefix = message.content.substr(0, myMention.length) + ' '; + } else { + return message.channel.send(`Current prefix: \`${prefix}\``); + }; + }; + if (message.content.indexOf(prefix) !== 0) return; const args = message.content.slice(prefix.length).trim().split(/ +/g); From 0360a5c581a4426fadd0f71aa45973e4be498532 Mon Sep 17 00:00:00 2001 From: FLGX Date: Thu, 19 Mar 2020 11:20:45 +0100 Subject: [PATCH 28/37] remove message content printing --- src/events/message.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/events/message.js b/src/events/message.js index f91dd7e..457706b 100644 --- a/src/events/message.js +++ b/src/events/message.js @@ -134,9 +134,7 @@ module.exports = async (client, message) => { //const prefixMention = new RegExp(`^<@!?${client.user.id}>( |)$`); const myMention = `<@&${client.user.id}>`; const myMention2 = `<@!${client.user.id}>`; - - console.log(message.content); - + if (message.content.startsWith(myMention) || message.content.startsWith(myMention2)) { if(message.content.length > myMention.length + 1 && (message.content.substr(0, myMention.length + 1) == myMention + ' ' || message.content.substr(0, myMention2.length + 1) == myMention2 + ' ')) { prefix = message.content.substr(0, myMention.length) + ' '; @@ -144,7 +142,7 @@ module.exports = async (client, message) => { return message.channel.send(`Current prefix: \`${prefix}\``); }; }; - + if (message.content.indexOf(prefix) !== 0) return; const args = message.content.slice(prefix.length).trim().split(/ +/g); From 9853c9032be6272d0f3d78d36495263f6de0cea2 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Thu, 19 Mar 2020 21:37:34 +1100 Subject: [PATCH 29/37] synced changes --- LICENSE.md | 3 +- changes.txt | 2 +- resources/other/coolpeople.json | 3 +- resources/other/genders.json | 13 ++++++- src/commands/colourify.js | 53 --------------------------- src/commands/help.js | 24 +++++++----- src/commands/ship.js | 4 +- src/commands/ship1.js | 65 --------------------------------- src/commands/userinfo.js | 14 +------ 9 files changed, 35 insertions(+), 146 deletions(-) delete mode 100644 src/commands/colourify.js delete mode 100644 src/commands/ship1.js diff --git a/LICENSE.md b/LICENSE.md index f82dfa5..4e230a1 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,7 @@ MIT License -Copyright (c) 2020 mudkipscience +Copyright (c) 2018 YorkAARGH +Copyright (c) 2018-2020 mudkipscience Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/changes.txt b/changes.txt index e91c096..529e5aa 100644 --- a/changes.txt +++ b/changes.txt @@ -4,7 +4,7 @@ Bots now get a bot badge in the userinfo command Added dogfact and catfact command (terry) index.js now has better logging of when things fail to load/initialize (terry) added `dice`, rolls a 6 sided die (terry) -Help command changed, the amount of commands in each category and overall is now displayed +Help command changed, the amount of commands in each category and overall is now displayed and formatting changed added `inspire` as an alias for inspirobot ship command added find by mention to functions \ No newline at end of file diff --git a/resources/other/coolpeople.json b/resources/other/coolpeople.json index f0de195..a2ec0bf 100644 --- a/resources/other/coolpeople.json +++ b/resources/other/coolpeople.json @@ -14,6 +14,7 @@ "264970229514371072", "254310746450690048", "358390849807319040", - "211011138656272386" + "211011138656272386", + "266472557740425216" ] } \ No newline at end of file diff --git a/resources/other/genders.json b/resources/other/genders.json index 3b50663..e09ea2d 100644 --- a/resources/other/genders.json +++ b/resources/other/genders.json @@ -1,4 +1,15 @@ { + "agender": "A gender identity used by someone who has no gender, or sometimes by someone whose gender is neutral", + "aporagender": "A gender that is not male, female, or anything on the spectrum between male and female, but that still has a distinct gendered feeling.", + "bigender": "Bigender individuals have two gender identities, either simultaneously or varying between the two.", "cisgender": "Someone who identifies with their assigned gender at birth.", - "transgender": "Someone who identifies with a gender that is not their assigned gender at birth." + "demiboy": "Someone who identifies as partially male and partially another gender.", + "demiflux": "A gender where one part of someone’s gender is static, and the other part fluctuates in intensity.", + "demigender": "Someone who identifies as partially one gender, and partially another.", + "demigirl": "Someone who identifies as partially female and partially another gender.", + "enby": "Shortened term for “nonbinary”. Used as a noun, like “boy” or “girl” but for nonbinary people.", + "genderfluid": "Someone whos gender varies over time. This might be fluctuating between different genders, or expressing multiple aspects of various genders at the same time.", + "genderflux": "Someone whose gender fluctuates, usually between agender and something else.", + "" + "transgender": "Someone whos gender is different from what they were assigned at birth." } \ No newline at end of file diff --git a/src/commands/colourify.js b/src/commands/colourify.js deleted file mode 100644 index f13720d..0000000 --- a/src/commands/colourify.js +++ /dev/null @@ -1,53 +0,0 @@ -const isURL = require("is-url") -exports.run = async (client, message, args) => { - var img; - if(!args[0]) { - if(!message.attachments.first()) { - return message.channel.send("No attachment") - }; - img = message.attachments.first().attachment; - } else { - if(isURL(args[0]) == true ) { - img = args[0]; - } else { - user = message.mentions.members.first(); - - if (!user) { - let users; - users = client.searchForMembers(message.guild, args[0]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user = users[0]; - }; - - if(user) { - img = user.user.avatarURL({format: "png", dynamic: true}) - } - } - }; - - var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/filter/magik?image=${img}`) - message.channel.send(attachment) -}; - - exports.conf = { - enabled: true, - guildOnly: false, - aliases: [], - permLevel: "User", - requiredPerms: [] - }; - - exports.help = { - name: "magikt", - category: "Fun", - description: "Colourifies an image", - usage: "colourify user hex1 hex2" - }; - \ No newline at end of file diff --git a/src/commands/help.js b/src/commands/help.js index beeda6d..0dd8acf 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -3,7 +3,7 @@ exports.run = (client, message, args, level) => { embed.setColor(client.embedColour(message)); var ran = false; - var output = ""; + var output = "```"; var commands = 0; var prefix; var currentCategory; @@ -38,18 +38,22 @@ exports.run = (client, message, args, level) => { const cat = c.help.category.toProperCase(); if (currentCategory !== cat) { if(ran == true) { - embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)) - output = ""; + output = output.slice(0, -2) + "```"; + embed.addField(currentCategory + ` [${commands}]`, output) + output = "```"; commands = 0; } currentCategory = cat; ran = true } - output += `\`${prefix}${c.help.name}\`, `; + output += `${prefix}${c.help.name}, `; commands = commands + 1; }); - embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)); + output = output.slice(0, -2); + output = output + "```" + + embed.addField(currentCategory + ` [${commands}]`, output); embed.addField( "Invite me", @@ -87,18 +91,20 @@ exports.run = (client, message, args, level) => { const cat = c.help.category.toProperCase(); if (currentCategory !== cat) { if(ran == true) { - embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)) - output = ""; + output = output.slice(0, -2) + "```"; + embed.addField(currentCategory + ` [${commands}]`, output) + output = "```"; commands = 0; } currentCategory = cat; ran = true } - output += `\`${prefix}${c.help.name}\`, `; + output += `${prefix}${c.help.name}, `; commands = commands + 1; }); - embed.addField(currentCategory + ` [${commands}]`, output.slice(0, -2)); + output = output.slice(0, -2) + "```"; + embed.addField(currentCategory + ` [${commands}]`, output); embed.addField( "Invite me", diff --git a/src/commands/ship.js b/src/commands/ship.js index 2ef0477..6264131 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -39,11 +39,9 @@ exports.run = async (client, message, args) => { ); user2 = users[0]; }; - - var secondLength = Math.floor(user2.username.length / 2); var first = user.username.slice(0, user.username.length / 2) - var second = user2.username.slice(secondLength, user2.username.length / 2) + var second = user2.username.slice(Math.floor(user2.username.length / 2), user2.username.length) try { var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) diff --git a/src/commands/ship1.js b/src/commands/ship1.js deleted file mode 100644 index ca96edd..0000000 --- a/src/commands/ship1.js +++ /dev/null @@ -1,65 +0,0 @@ -const request = require('request') -exports.run = async (client, message, args) => { - - - //NOT FINISHED - - if(!args[0] || !args[1]) { - return message.channel.send(`<:error:466995152976871434> Please include two to five users`) - } - message.channel.startTyping(); - - var user = client.getUserFromMention(args[0]) - var user2 = client.getUserFromMention(args[1]) - - if (!user) { - let users; - users = client.searchForMembers(message.guild, args[0]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user = users[0]; - }; - - if (!user2) { - let users; - users = client.searchForMembers(message.guild, args[0]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user2 = users[0]; - }; - - var secondLength = Math.floor(user2.username.length / 2); - - var first = user.username.slice(0, user.username.length / 2) - var second = user2.username.slice(secondLength, user2.username.length / 2) - - message.channel.send(`Your ship name is **${shipname}!**`) -}; - -exports.conf = { - enabled: true, - guildOnly: true, - aliases: [], - permLevel: "User", - requiredPerms: [] -}; - -exports.help = { - name: "ship1", - category: "Fun", - description: "Ship two people together <3", - usage: "ship name name2" -}; - diff --git a/src/commands/userinfo.js b/src/commands/userinfo.js index ddec46f..c5dcbac 100644 --- a/src/commands/userinfo.js +++ b/src/commands/userinfo.js @@ -1,18 +1,8 @@ const Discord = require("discord.js"); const coolPeople = require('../../resources/other/coolpeople.json') exports.run = (client, message, args) => { - var user; - var guild; - var nick = ""; - var roles = ""; - var presence = ""; - var badges = ""; - var status; - var createdAt; - var avurl; - var tag; - var id; - var bot; + var user, guild, status, createdAt, avurl, tag, id; + var nick, roles, presence, badges = ""; var coolPerson = false; var friendos = coolPeople.coolPeople; From 4948a5d1f5c8ed5bf9982a0297331312fad10346 Mon Sep 17 00:00:00 2001 From: FLGX Date: Thu, 19 Mar 2020 11:46:10 +0100 Subject: [PATCH 30/37] fix ship command --- src/commands/ship.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/ship.js b/src/commands/ship.js index 2ef0477..a3207e2 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -23,12 +23,12 @@ exports.run = async (client, message, args) => { return message.channel.send( "<:error:466995152976871434> That user doesn't seem to exist. Try again!" ); - user = users[0]; + user = users[0].user; }; if (!user2) { let users; - users = client.searchForMembers(message.guild, args[0]); + users = client.searchForMembers(message.guild, args[1]); if (users.length > 1) return message.channel.send( "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." @@ -37,13 +37,13 @@ exports.run = async (client, message, args) => { return message.channel.send( "<:error:466995152976871434> That user doesn't seem to exist. Try again!" ); - user2 = users[0]; + user2 = users[0].user; }; var secondLength = Math.floor(user2.username.length / 2); - var first = user.username.slice(0, user.username.length / 2) - var second = user2.username.slice(secondLength, user2.username.length / 2) + var first = user.username.slice(0, secondLength - 1) + var second = user2.username.slice(secondLength) try { var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) From f87c2834665f5f836ecbbdb5fd7645d95499f4f5 Mon Sep 17 00:00:00 2001 From: FLGX Date: Thu, 19 Mar 2020 11:50:30 +0100 Subject: [PATCH 31/37] a --- src/commands/ship1.js | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/commands/ship1.js diff --git a/src/commands/ship1.js b/src/commands/ship1.js new file mode 100644 index 0000000..39d2621 --- /dev/null +++ b/src/commands/ship1.js @@ -0,0 +1,70 @@ +const request = require('request') +exports.run = async (client, message, args) => { + + + //NOT FINISHED + + if(!args[0] || !args[1]) { + return message.channel.send(`<:error:466995152976871434> Please include two users`) + } + message.channel.startTyping(); + + var user = client.getUserFromMention(args[0]) + var user2 = client.getUserFromMention(args[1]) + + if (!user) { + let users; + users = client.searchForMembers(message.guild, args[0]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].user; + }; + + if (!user2) { + let users; + users = client.searchForMembers(message.guild, args[1]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user2 = users[0].user; + }; + + var first = user.username.slice(0, secondLength - 1) + var second = user2.username.slice(secondLength) + + try { + var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) + message.channel.send(`Your ship name is **${first+second}!**`, attachment) + message.channel.stopTyping(); + } catch(err) { + message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "ship1", + category: "Fun", + description: "Ship two people together <3", + usage: "ship1 name name2" +}; + From 8a1f87b993f8e99a6cf9872e32152e06b48a9afd Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Fri, 20 Mar 2020 12:08:52 +1100 Subject: [PATCH 32/37] Renamed ~gender to ~identity --- resources/other/genders.json | 15 ----- resources/other/identities.json | 110 ++++++++++++++++++++++++++++++++ src/commands/identity.js | 31 +++++++++ 3 files changed, 141 insertions(+), 15 deletions(-) delete mode 100644 resources/other/genders.json create mode 100644 resources/other/identities.json create mode 100644 src/commands/identity.js diff --git a/resources/other/genders.json b/resources/other/genders.json deleted file mode 100644 index e09ea2d..0000000 --- a/resources/other/genders.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "agender": "A gender identity used by someone who has no gender, or sometimes by someone whose gender is neutral", - "aporagender": "A gender that is not male, female, or anything on the spectrum between male and female, but that still has a distinct gendered feeling.", - "bigender": "Bigender individuals have two gender identities, either simultaneously or varying between the two.", - "cisgender": "Someone who identifies with their assigned gender at birth.", - "demiboy": "Someone who identifies as partially male and partially another gender.", - "demiflux": "A gender where one part of someone’s gender is static, and the other part fluctuates in intensity.", - "demigender": "Someone who identifies as partially one gender, and partially another.", - "demigirl": "Someone who identifies as partially female and partially another gender.", - "enby": "Shortened term for “nonbinary”. Used as a noun, like “boy” or “girl” but for nonbinary people.", - "genderfluid": "Someone whos gender varies over time. This might be fluctuating between different genders, or expressing multiple aspects of various genders at the same time.", - "genderflux": "Someone whose gender fluctuates, usually between agender and something else.", - "" - "transgender": "Someone whos gender is different from what they were assigned at birth." -} \ No newline at end of file diff --git a/resources/other/identities.json b/resources/other/identities.json new file mode 100644 index 0000000..c37d5d9 --- /dev/null +++ b/resources/other/identities.json @@ -0,0 +1,110 @@ +{ + "agender": { + "name": "agender", + "description": "A gender identity used by someone who has no gender, or sometimes by someone whose gender is neutral." + }, + "androgyne": { + "name": "androgyne", + "description": "A gender identity associated with androgyny. Androgynes have a gender which is simultaneously feminine and masculine, although not necessarily in equal amounts." + }, + "androgynous": { + "name": "androgynous", + "description": "A term used to refer to people who have both feminine and masculine characteristics." + }, + "aporagender": { + "name": "aporagender", + "description": "A gender that is not male, female, or anything in between that still has a distinct gendered feeling." + }, + "bigender": { + "name": "bigender", + "description": "Having two gender identities, either simultaneously or varying between the two." + }, + "cisgender": { + "name": "cisgender", + "description": "Someone who identifies with their assigned gender at birth." + }, + "demiboy": { + "name": "demiboy", + "description": "Someone who identifies as partially male and partially another gender." + }, + "demiflux": { + "name": "demiflux", + "description": "A gender where one part of someone’s gender is static, and the other part fluctuates in intensity." + }, + "demigender": { + "name": "demigender", + "description": "Someone who identifies as partially one gender, and partially another." + }, + "demigirl": { + "name": "demigirl", + "description": "Someone who identifies as partially female and partially another gender." + }, + "dyadic": { + "name": "dyadic", + "description": "A word used to refer to people who are not intersex" + }, + "enby": { + "name": "enby", + "description": "Shortened term for “nonbinary”. Used as a noun, like “boy” or “girl” but for nonbinary people." + }, + "fluidflux": { + "name": "fluidflux", + "description": "A gender identity which refers to someone with a gender that moves between two or more genders and also fluctuates in intensity." + }, + "genderfluid": { + "name": "genderfluid", + "description": "Someone whose gender varies over time. This might be fluctuating between different genders, or expressing multiple aspects of various genders at the same time." + }, + "genderflux": { + "name": "genderflux", + "description": "Someone whose gender fluctuates, usually between agender and something else." + }, + "genderqueer": { + "name": "genderqueer", + "description": "An umbrella term for all the nonbinary genders. Genderqueer can be a standalone identity, or can refer to a more specific gender identity." + }, + "gendervoid": { + "name": "gendervoid", + "description": "Someone who does not experience gender, or who feels an absence or void in the place of gender." + }, + "intersex": { + "name": "intersex", + "description": "An intersex person is someone with sex characteristics (sexual anatomy, reproductive organs, chromosomal patterns, etc.) that do not align with the typical descriptions of male and female." + }, + "libragender": { + "name": "libragender", + "description": "A gender identity that is mostly agender, but has a connection to masculinity and/or femininity and/or other gendered feelings. That connection may be static (libragender, librafeminine, libramasculine, etc) or fluid, where one feels that the gender one experiences changes (librafluid)." + }, + "neutrois": { + "name": "neutrois", + "description": "Having a null or neutral gender." + }, + "nonbinary": { + "name": "nonbinary", + "description": "An umbrella term for all the gender identities that aren't male or female (the binary genders)" + }, + "non-gendered": { + "name": "non-gendered", + "description": "Having no gender." + }, + "polygender": { + "name": "polygender", + "description": "Having more than one gender, either at the same time or at different times. A polygender person may identify with any combination of binary and nonbinary genders." + }, + "pangender": { + "name": "pangender", + "description": "Having more than one gender, especially someone who identifies as all genders." + }, + "transfeminine": { + "name": "transfeminine", + "description": "A transgender person who identifies with femininity, either as a binary female or a fem-leaning nonbinary identity." + }, + "transgender": { + "name": "transgender", + "description": "An umbrella term that refers to people whose identity differs from their assigned gender at birth." + }, + "transmasculine": { + "name": "transmasculine", + "description": "A transgender person who identifies with masculinity, either as a binary male or a masc-leaning nonbinary identity." + } +} \ No newline at end of file diff --git a/src/commands/identity.js b/src/commands/identity.js new file mode 100644 index 0000000..9be25a4 --- /dev/null +++ b/src/commands/identity.js @@ -0,0 +1,31 @@ +const identities = require ("../../resources/other/identities.json"); +exports.run = async (client, message, args) => { + var output = ""; + if(!args[0]) { + for (var key of Object.keys(identities)) { + output += `${key}, ` + }; + return message.channel.send(`__**Identities**__\n${output.slice(0, -2)}`); + } else { + output = identities[args[0].toLowerCase()]; + if(!output) { + return message.channel.send("<:error:466995152976871434> No results for that query."); + }; + return message.channel.send(`__**${output.name}**__\n${output.description}`); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "identity", + category: "Fun", + description: "Gives you information about the specified identity.", + usage: "identity [identity]" +}; From 29e8198126ed6c82ef6881604c7015b582e13296 Mon Sep 17 00:00:00 2001 From: FLGX Date: Sat, 21 Mar 2020 10:46:51 +0100 Subject: [PATCH 33/37] aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --- src/commands/ship.js | 80 ++++++++++++++++++++++++++----------------- src/commands/ship1.js | 70 ------------------------------------- 2 files changed, 48 insertions(+), 102 deletions(-) delete mode 100644 src/commands/ship1.js diff --git a/src/commands/ship.js b/src/commands/ship.js index c10855f..1fe3c57 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -9,43 +9,59 @@ exports.run = async (client, message, args) => { } message.channel.startTyping(); - var user = client.getUserFromMention(args[0]) - var user2 = client.getUserFromMention(args[1]) + let users = []; + let totalLength = 0; - if (!user) { - let users; - users = client.searchForMembers(message.guild, args[0]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user = users[0].user; + for(let i = 0; i < args.length; i++) { + let arg = args[i]; + + let user = client.getUserFromMention(arg); + + if(!user) { + let usersFound; + usersFound = client.searchForMembers(message.guild, arg); + if (usersFound.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." + ); + else if (usersFound.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = usersFound[0].user; + } + + users.push(user); + totalLength += user.username.length; + } + + let lengthPerUser = Math.floor(totalLength / users.length); + + let finalName = ''; + + let last = -1; + + for(let i = 0; i < users.length; i++) { + let user = users[i]; + let l = Math.min(lengthPerUser, user.username.length); + + let p = user.username.substr(last + 1, last + l); + + console.log(p); + + finalName = finalName + p; + + last = last + l; }; - if (!user2) { - let users; - users = client.searchForMembers(message.guild, args[1]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user2 = users[0].user; - }; - - var first = user.username.slice(0, user.username.length / 2) - var second = user2.username.slice(Math.floor(user2.username.length / 2), user2.username.length) + console.log(totalLength); + console.log(users.length); + console.log(lengthPerUser); + console.log(finalName); try { - var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) - message.channel.send(`Your ship name is **${first+second}!**`, attachment) + //var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) + message.channel.send(`Your ship name is **${finalName}!**`) message.channel.stopTyping(); } catch(err) { message.channel.send(`<:error:466995152976871434> API error: ${err}`); diff --git a/src/commands/ship1.js b/src/commands/ship1.js deleted file mode 100644 index 39d2621..0000000 --- a/src/commands/ship1.js +++ /dev/null @@ -1,70 +0,0 @@ -const request = require('request') -exports.run = async (client, message, args) => { - - - //NOT FINISHED - - if(!args[0] || !args[1]) { - return message.channel.send(`<:error:466995152976871434> Please include two users`) - } - message.channel.startTyping(); - - var user = client.getUserFromMention(args[0]) - var user2 = client.getUserFromMention(args[1]) - - if (!user) { - let users; - users = client.searchForMembers(message.guild, args[0]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user = users[0].user; - }; - - if (!user2) { - let users; - users = client.searchForMembers(message.guild, args[1]); - if (users.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (users.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user2 = users[0].user; - }; - - var first = user.username.slice(0, secondLength - 1) - var second = user2.username.slice(secondLength) - - try { - var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) - message.channel.send(`Your ship name is **${first+second}!**`, attachment) - message.channel.stopTyping(); - } catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); - message.channel.stopTyping(); - }; -}; - -exports.conf = { - enabled: true, - guildOnly: true, - aliases: [], - permLevel: "User", - requiredPerms: [] -}; - -exports.help = { - name: "ship1", - category: "Fun", - description: "Ship two people together <3", - usage: "ship1 name name2" -}; - From 282c61261dfa288d2d1d91997e149b42f720c74b Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Sun, 22 Mar 2020 22:13:41 +1100 Subject: [PATCH 34/37] Synced changes --- changes.txt | 5 +- package.json | 2 +- resources/images/attackhelicopter.jpg | Bin 0 -> 101789 bytes resources/other/coolpeople.json | 3 +- resources/other/identities.json | 2 +- resources/other/pronouns.json | 153 ++++++++++++++++++++++++- resources/other/sexualities.json | 101 +++++++++++++++- src/commands/{math.js => calculate.js} | 6 +- src/commands/emoji.js | 1 - src/commands/identity.js | 11 +- src/commands/pronoun.js | 36 ++++++ src/commands/sexuality.js | 36 ++++++ src/commands/ship.js | 64 ++++------- 13 files changed, 367 insertions(+), 53 deletions(-) create mode 100644 resources/images/attackhelicopter.jpg rename src/commands/{math.js => calculate.js} (92%) create mode 100644 src/commands/pronoun.js create mode 100644 src/commands/sexuality.js diff --git a/changes.txt b/changes.txt index 529e5aa..2648987 100644 --- a/changes.txt +++ b/changes.txt @@ -7,4 +7,7 @@ added `dice`, rolls a 6 sided die (terry) Help command changed, the amount of commands in each category and overall is now displayed and formatting changed added `inspire` as an alias for inspirobot ship command -added find by mention to functions \ No newline at end of file +added find by mention to functions +you can now @mention the bot to run commands +added identity command, has definitions of gender identities and stuff +renamed math calculate diff --git a/package.json b/package.json index 1c03415..901ffbf 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "better-sqlite3": "^5.4.1", "chalk": "^3.0.0", "dblapi.js": "^2.3.1", - "discord.js": "^12.0.1", + "discord.js": "^12.0.2", "enmap": "^5.2.4", "garfield": "^1.1.2", "get-youtube-id": "^1.0.1", diff --git a/resources/images/attackhelicopter.jpg b/resources/images/attackhelicopter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c077f0d0f97251402063f0982e20d381590fc427 GIT binary patch literal 101789 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

LP?s}>_8ENxMl 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 { exports.conf = { enabled: true, guildOnly: false, - aliases: ["calculate", "calc"], + aliases: ["calc", "math"], permLevel: "User", requiredPerms: [] }; exports.help = { - name: "math", + name: "calculate", category: "Utility", description: "Solves basic mathematical equations.", - usage: "math [equation]" + usage: "calculate [equation]" }; \ No newline at end of file diff --git a/src/commands/emoji.js b/src/commands/emoji.js index 795686c..ab6907b 100644 --- a/src/commands/emoji.js +++ b/src/commands/emoji.js @@ -11,7 +11,6 @@ exports.run = async (client, message, args) => { format = ".gif" }; - console.log(string.length) if(string.length > 18) { ID = string.slice(string.length - 18); } else { diff --git a/src/commands/identity.js b/src/commands/identity.js index 9be25a4..22e8693 100644 --- a/src/commands/identity.js +++ b/src/commands/identity.js @@ -6,8 +6,13 @@ exports.run = async (client, message, args) => { output += `${key}, ` }; return message.channel.send(`__**Identities**__\n${output.slice(0, -2)}`); - } else { - output = identities[args[0].toLowerCase()]; + } else { + if(args.join(" ").toLowerCase() == "attack helicopter" || args.join(" ").toLowerCase() == "apache attack helicopter" || args.join(" ").toLowerCase() == "apache") { + return message.channel.send({ + files: [new Discord.MessageAttachment("./resources/images/attackhelicopter.jpg")] + }); + } + output = identities[args.join(" ").toLowerCase()]; if(!output) { return message.channel.send("<:error:466995152976871434> No results for that query."); }; @@ -18,7 +23,7 @@ exports.run = async (client, message, args) => { exports.conf = { enabled: true, guildOnly: false, - aliases: [], + aliases: ["identities"], permLevel: "User", requiredPerms: [] }; diff --git a/src/commands/pronoun.js b/src/commands/pronoun.js new file mode 100644 index 0000000..a535647 --- /dev/null +++ b/src/commands/pronoun.js @@ -0,0 +1,36 @@ +const pronouns = require ("../../resources/other/pronouns.json"); +exports.run = async (client, message, args) => { + var output = ""; + if(!args[0]) { + for (var key of Object.keys(pronouns)) { + output += `${key}, ` + }; + return message.channel.send(`__**Pronouns**__\n${output.slice(0, -2)}`); + } else { + if(args.join(" ").toLowerCase() == "attack helicopter" || args.join(" ").toLowerCase() == "apache attack helicopter" || args.join(" ").toLowerCase() == "apache") { + return message.channel.send({ + files: [new Discord.MessageAttachment("./resources/images/attackhelicopter.jpg")] + }); + }; + output = pronouns[args.join(" ").toLowerCase()]; + if(!output) { + return message.channel.send("<:error:466995152976871434> No results for that query."); + }; + return message.channel.send(`__**Example sentences using ${output.name}**__\n${output.examples}`); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["pronouns"], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "pronoun", + category: "Fun", + description: "Gives you information on how to use the specified pronoun.", + usage: "pronoun [pronoun]" +}; diff --git a/src/commands/sexuality.js b/src/commands/sexuality.js new file mode 100644 index 0000000..8507dac --- /dev/null +++ b/src/commands/sexuality.js @@ -0,0 +1,36 @@ +const sexualities = require ("../../resources/other/sexualities.json"); +exports.run = async (client, message, args) => { + var output = ""; + if(!args[0]) { + for (var key of Object.keys(sexualities)) { + output += `${key}, ` + }; + return message.channel.send(`__**sexualities**__\n${output.slice(0, -2)}`); + } else { + if(args.join(" ").toLowerCase() == "attack helicopter" || args.join(" ").toLowerCase() == "apache attack helicopter" || args.join(" ").toLowerCase() == "apache") { + return message.channel.send({ + files: [new Discord.MessageAttachment("./resources/images/attackhelicopter.jpg")] + }); + } + output = sexualities[args.join(" ").toLowerCase()]; + if(!output) { + return message.channel.send("<:error:466995152976871434> No results for that query."); + }; + return message.channel.send(`__**${output.name}**__\n${output.description}`); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["sexualities"], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "sexuality", + category: "Fun", + description: "Gives you information about the specified sexuality.", + usage: "sexuality [sexuality]" +}; diff --git a/src/commands/ship.js b/src/commands/ship.js index 1fe3c57..8d8fef3 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -1,51 +1,42 @@ -const request = require('request') exports.run = async (client, message, args) => { - - //NOT FINISHED + var hearts = [ + "❤️", + "🧡", + "💛", + "💚", + "💙", + "💜" + ]; if(!args[0] || !args[1]) { - return message.channel.send(`<:error:466995152976871434> Please include two users`) + return message.channel.send(`<:error:466995152976871434> Please include at least two names.`) } - message.channel.startTyping(); - let users = []; + let names = []; let totalLength = 0; for(let i = 0; i < args.length; i++) { let arg = args[i]; - - let user = client.getUserFromMention(arg); - - if(!user) { - let usersFound; - usersFound = client.searchForMembers(message.guild, arg); - if (usersFound.length > 1) - return message.channel.send( - "<:error:466995152976871434> Found multiple users! Please be more specific or mention the user instead." - ); - else if (usersFound.length == 0) - return message.channel.send( - "<:error:466995152976871434> That user doesn't seem to exist. Try again!" - ); - user = usersFound[0].user; - } - - users.push(user); - totalLength += user.username.length; + let name = client.getUserFromMention(arg).username; + if(!name) { + name = arg; + }; + names.push(name); + totalLength += arg.length; } - let lengthPerUser = Math.floor(totalLength / users.length); + let lengthPerName = Math.floor(totalLength / names.length); let finalName = ''; let last = -1; - for(let i = 0; i < users.length; i++) { - let user = users[i]; - let l = Math.min(lengthPerUser, user.username.length); + for(let i = 0; i < names.length; i++) { + let name = names[i]; + let l = Math.min(lengthPerName, name.length); - let p = user.username.substr(last + 1, last + l); + let p = name.substr(last + 1, last + l); console.log(p); @@ -55,18 +46,11 @@ exports.run = async (client, message, args) => { }; console.log(totalLength); - console.log(users.length); - console.log(lengthPerUser); + console.log(names.length); + console.log(lengthPerName); console.log(finalName); - try { - //var attachment = new Discord.MessageAttachment(`https://api.alexflipnote.dev/ship?user=${user.avatarURL({format: "png"})}&user2=${user2.avatarURL({format: "png"})}`) - message.channel.send(`Your ship name is **${finalName}!**`) - message.channel.stopTyping(); - } catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); - message.channel.stopTyping(); - }; + message.channel.send(`**Ship generator:**\n${hearts.random()} Ship name: \`${finalName}\`\n${hearts.random()} Compatibility rating:`) }; exports.conf = { From 063a5ab4659577cc7088ded6f84c86d7b4ba516b Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Mon, 23 Mar 2020 00:01:54 +1100 Subject: [PATCH 35/37] Synced changes --- changes.txt | 6 ++- src/commands/{creeper.js => dice.js} | 0 src/commands/diceroll.js | 2 +- src/commands/roleinfo.js | 45 +++++++++++++++++---- src/commands/ship.js | 59 ++++++++++------------------ src/events/message.js | 2 +- src/modules/functions.js | 6 +++ 7 files changed, 72 insertions(+), 48 deletions(-) rename src/commands/{creeper.js => dice.js} (100%) diff --git a/changes.txt b/changes.txt index 2648987..f121500 100644 --- a/changes.txt +++ b/changes.txt @@ -3,11 +3,15 @@ Links to avatars now lead to the original file size Bots now get a bot badge in the userinfo command Added dogfact and catfact command (terry) index.js now has better logging of when things fail to load/initialize (terry) -added `dice`, rolls a 6 sided die (terry) +added `dice`, rolls a sided die (terry) Help command changed, the amount of commands in each category and overall is now displayed and formatting changed added `inspire` as an alias for inspirobot ship command added find by mention to functions you can now @mention the bot to run commands added identity command, has definitions of gender identities and stuff +added pronouns command, tells you how to use pronouns +added sexuality command, has definitions of sexualities renamed math calculate +fixed woomy in dms +roleinfo now displays what permissions a role has and also the role colour in the thumbnail diff --git a/src/commands/creeper.js b/src/commands/dice.js similarity index 100% rename from src/commands/creeper.js rename to src/commands/dice.js diff --git a/src/commands/diceroll.js b/src/commands/diceroll.js index b307d4e..65900c8 100644 --- a/src/commands/diceroll.js +++ b/src/commands/diceroll.js @@ -22,6 +22,6 @@ exports.run = async (bot, message, args) => { name: "dice", category: "Fun", description: "Rolls a dice.", - usage: "dice" + usage: "dice **OR** dice " }; diff --git a/src/commands/roleinfo.js b/src/commands/roleinfo.js index f6fd0e0..e6c95a4 100644 --- a/src/commands/roleinfo.js +++ b/src/commands/roleinfo.js @@ -15,17 +15,48 @@ exports.run = async (client, message, args, level) => { return message.channel.send(`<:error:466995152976871434> Role not found.`) } - if(role.hoist === true) { - var hoist = `Yes` - } else { - var hoist = `No` - } + var permissions = "```"; + if(role.permissions.has("ADMINISTRATOR")) permissions += "ADMINISTRATOR, "; + if(role.permissions.has("CREATE_INSTANT_INVITE")) permissions += "CREATE_INSTANT_INVITE, "; + if(role.permissions.has("KICK_MEMBERS")) permissions += "KICK_MEMBERS, "; + if(role.permissions.has("BAN_MEMBERS")) permissions += "BAN_MEMBERS, "; + if(role.permissions.has("MANAGE_CHANNELS")) permissions += "MANAGE_CHANNELS, "; + if(role.permissions.has("MANAGE_GUILD")) permissions += "MANAGE_GUILD, "; + if(role.permissions.has("ADD_REACTIONS")) permissions += "ADD_REACTIONS, "; + if(role.permissions.has("VIEW_AUDIT_LOG")) permissions += "VIEW_AUDIT_LOG, "; + if(role.permissions.has("PRIORITY_SPEAKER")) permissions += "PRIORITY_SPEAKER, "; + if(role.permissions.has("STREAM")) permissions += "STREAM, "; + if(role.permissions.has("VIEW_CHANNEL")) permissions += "VIEW_CHANNEL, "; + if(role.permissions.has("SEND_MESSAGES")) permissions += "SEND_MESSAGES, "; + if(role.permissions.has("SEND_TTS_MESSAGES")) permissions += "SEND_TTS_MESSAGES, "; + if(role.permissions.has("MANAGE_MESSAGES")) permissions += "MANAGE_MESSAGES, "; + if(role.permissions.has("EMBED_LINKS")) permissions += "EMBED_LINKS, "; + if(role.permissions.has("ATTACH_FILES")) permissions += "ATTACH_FILES, "; + if(role.permissions.has("READ_MESSAGE_HISTORY")) permissions += "READ_MESSAGE_HISTORY, "; + if(role.permissions.has("MENTION_EVERYONE")) permissions += "MENTION_EVERYONE, "; + if(role.permissions.has("USE_EXTERNAL_EMOJIS")) permissions += "USE_EXTERNAL_EMOJIS, "; + if(role.permissions.has("CONNECT")) permissions += "CONNECT, "; + if(role.permissions.has("SPEAK")) permissions += "SPEAK, "; + if(role.permissions.has("MUTE_MEMBERS")) permissions += "MUTE_MEMBERS, "; + if(role.permissions.has("DEAFEN_MEMBERS")) permissions += "DEAFEN_MEMBERS, "; + if(role.permissions.has("MOVE_MEMBERS")) permissions += "MOVE_MEMBERS, "; + if(role.permissions.has("USE_VAD")) permissions += "USE_VAD, "; + if(role.permissions.has("CHANGE_NICKNAME")) permissions += "CHANGE_NICKNAME, "; + if(role.permissions.has("MANAGE_NICKNAMES")) permissions += "MANAGE_NICKNAMES, "; + if(role.permissions.has("MANAGE_ROLES")) permissions += "MANAGE_ROLES, "; + if(role.permissions.has("MANAGE_WEBHOOKS")) permissions += "MANAGE_WEBHOOKS, "; + if(role.permissions.has("MANAGE_EMOJIS")) permissions += "MANAGE_EMOJIS, "; + permissions = permissions.slice(0, -2); + permissions += "```"; var embed = new Discord.MessageEmbed(); - embed.setColor(role.color) + embed.setColor(role.color); + embed.setTitle(role.name); + embed.setThumbnail("https://api.alexflipnote.xyz/colour/image/" + role.hexColor.replace("#", "")); embed.setDescription( - `• **Name:** ${role.name}\n• **ID:** ${role.id}\n• **Hex:** ${role.hexColor}\n• **Members:** ${role.members.size}\n• **Position:** ${role.position}\n• **Hoisted:** ${hoist}` + `• **ID:** ${role.id}\n• **Hex:** ${role.hexColor}\n• **Members:** ${role.members.size}\n• **Position:** ${role.position}\n• **Hoisted:** ${role.hoist}` ); + embed.addField(`**Permissions:**`, permissions) message.channel.send(embed) }; diff --git a/src/commands/ship.js b/src/commands/ship.js index 8d8fef3..7a68e00 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -1,5 +1,7 @@ exports.run = async (client, message, args) => { + var name, name1; + var rating = Math.floor(Math.random() * 100) + 1; var hearts = [ "❤️", "🧡", @@ -9,53 +11,34 @@ exports.run = async (client, message, args) => { "💜" ]; - if(!args[0] || !args[1]) { - return message.channel.send(`<:error:466995152976871434> Please include at least two names.`) + if(args.length < 2) { + return message.channel.send(`<:error:466995152976871434> Please include two names/users.`) } - let names = []; - let totalLength = 0; - - for(let i = 0; i < args.length; i++) { - let arg = args[i]; - let name = client.getUserFromMention(arg).username; - if(!name) { - name = arg; - }; - names.push(name); - totalLength += arg.length; - } - - let lengthPerName = Math.floor(totalLength / names.length); - - let finalName = ''; - - let last = -1; - - for(let i = 0; i < names.length; i++) { - let name = names[i]; - let l = Math.min(lengthPerName, name.length); - - let p = name.substr(last + 1, last + l); - - console.log(p); - - finalName = finalName + p; - - last = last + l; + if(message.guild && message.mentions.members && message.mentions.members.size > 0) { + name = message.mentions.members.first().displayName; }; - console.log(totalLength); - console.log(names.length); - console.log(lengthPerName); - console.log(finalName); + if(message.guild && message.mentions.members && message.mentions.members.size > 1) { + name1 = message.mentions.members.last().displayName; + }; - message.channel.send(`**Ship generator:**\n${hearts.random()} Ship name: \`${finalName}\`\n${hearts.random()} Compatibility rating:`) + if(!name) { + name = args[0]; + }; + + if(!name1) { + name1 = args[1]; + }; + + shipName = name.substring(0, client.intBetween(1,name.length))+name1.substring(client.intBetween(0,name1.length)); + + message.channel.send(`__**Ship Generator:**__\n${hearts.random()} Ship Name: \`${shipName}\`\n${hearts.random()} Compatibility rating: \`${rating}%\``) }; exports.conf = { enabled: true, - guildOnly: true, + guildOnly: false, aliases: [], permLevel: "User", requiredPerms: [] diff --git a/src/events/message.js b/src/events/message.js index 457706b..0dfc019 100644 --- a/src/events/message.js +++ b/src/events/message.js @@ -158,7 +158,7 @@ module.exports = async (client, message) => { .then(m => m.delete(2000)); }; - if (!perms.has('SEND_MESSAGES')) { + if (message.guild && !perms.has('SEND_MESSAGES')) { return message.author.send(`<:error:466995152976871434> I don't have permission to speak in **#${message.channel.name}**, Please ask a moderator to give me the send messages permission!`); }; diff --git a/src/modules/functions.js b/src/modules/functions.js index bd30579..f51a34d 100644 --- a/src/modules/functions.js +++ b/src/modules/functions.js @@ -340,6 +340,12 @@ module.exports = client => { }; }; + // FIND RANDOM INT BETWEEN TWO INTEGERS + client.intBetween = function(min, max){ + return Math.round((Math.random() * (max - min))+min); + }; + + // .toPropercase() returns a proper-cased string Object.defineProperty(String.prototype, "toProperCase", { value: function() { From 0fc9659b9ca6231bdfe6c3169c7d528a400b9516 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Mon, 23 Mar 2020 00:02:30 +1100 Subject: [PATCH 36/37] oosp forgot a thing --- src/commands/ship.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/ship.js b/src/commands/ship.js index 7a68e00..b11a988 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -48,6 +48,6 @@ exports.help = { name: "ship", category: "Fun", description: "Ship two people together <3", - usage: "ship name name2" + usage: "ship [name/user] [name/user]" }; From 3ec4d08763874f06912cb8d1d31615a90e9df260 Mon Sep 17 00:00:00 2001 From: mudkipscience Date: Thu, 26 Mar 2020 15:31:32 +1100 Subject: [PATCH 37/37] Update time woo --- changes.txt | 22 ++++++ index.js | 98 ++++++++------------------- package.json | 9 +-- src/commands/about.js | 2 +- src/commands/cat.js | 30 ++++++++ src/commands/catfact.js | 12 ++-- src/commands/{flip.js => coinflip.js} | 6 +- src/commands/credits.js | 4 +- src/commands/creeper.js | 45 ++++++++++++ src/commands/cuddle.js | 69 +++++++++++++++++++ src/commands/dice.js | 70 +++++++------------ src/commands/diceroll.js | 27 -------- src/commands/dog.js | 30 ++++++++ src/commands/dogfact.js | 17 +++-- src/commands/emojify.js | 2 +- src/commands/fact.js | 30 ++++++++ src/commands/feed.js | 69 +++++++++++++++++++ src/commands/feedback.js | 2 +- src/commands/foxgirl.js | 30 ++++++++ src/commands/help.js | 25 +++---- src/commands/hug.js | 69 +++++++++++++++++++ src/commands/identity.js | 2 +- src/commands/inspirobot.js | 25 +++---- src/commands/kemonomimi.js | 30 ++++++++ src/commands/kiss.js | 69 +++++++++++++++++++ src/commands/lizard.js | 30 ++++++++ src/commands/neko.js | 30 ++++++++ src/commands/nekogif.js | 30 ++++++++ src/commands/owoify.js | 4 +- src/commands/pat.js | 69 +++++++++++++++++++ src/commands/poke.js | 69 +++++++++++++++++++ src/commands/pronoun.js | 4 +- src/commands/roleinfo.js | 1 - src/commands/sexuality.js | 4 +- src/commands/ship.js | 2 +- src/commands/slap.js | 69 +++++++++++++++++++ src/commands/smug.js | 33 +++++++++ src/commands/spoilerise.js | 28 ++++++++ src/commands/support.js | 2 +- src/commands/tickle.js | 69 +++++++++++++++++++ src/commands/weather.js | 75 ++++++++++---------- src/commands/yoda.js | 37 +++++----- src/commands/zalgo.js | 30 ++++++++ src/events/ready.js | 19 ++++-- src/modules/functions.js | 19 +++--- 45 files changed, 1139 insertions(+), 279 deletions(-) create mode 100644 src/commands/cat.js rename src/commands/{flip.js => coinflip.js} (90%) create mode 100644 src/commands/creeper.js create mode 100644 src/commands/cuddle.js delete mode 100644 src/commands/diceroll.js create mode 100644 src/commands/dog.js create mode 100644 src/commands/fact.js create mode 100644 src/commands/feed.js create mode 100644 src/commands/foxgirl.js create mode 100644 src/commands/hug.js create mode 100644 src/commands/kemonomimi.js create mode 100644 src/commands/kiss.js create mode 100644 src/commands/lizard.js create mode 100644 src/commands/neko.js create mode 100644 src/commands/nekogif.js create mode 100644 src/commands/pat.js create mode 100644 src/commands/poke.js create mode 100644 src/commands/slap.js create mode 100644 src/commands/smug.js create mode 100644 src/commands/spoilerise.js create mode 100644 src/commands/tickle.js create mode 100644 src/commands/zalgo.js diff --git a/changes.txt b/changes.txt index f121500..8ca32e2 100644 --- a/changes.txt +++ b/changes.txt @@ -15,3 +15,25 @@ added sexuality command, has definitions of sexualities renamed math calculate fixed woomy in dms roleinfo now displays what permissions a role has and also the role colour in the thumbnail +request has been replaced with node-fetch +added neko +added fact +added nekogif +added dog +added cat +added hug +added kiss +added pat +added poke +added slap +added tickle +added cuddle +added feed +added smug +added lizard +added kemonomimi +added spoilerise +added zalgo +renamed flip coinflip +small changes to weather +recategorised some commands diff --git a/index.js b/index.js index 4e535ee..395e910 100644 --- a/index.js +++ b/index.js @@ -1,84 +1,55 @@ +if (Number(process.version.slice(1).split(".")[0]) < 12) { + throw new Error("Node 12.0.0 or higher is required. Please update Node on your system."); +}; + const Discord = require('discord.js'); const { promisify } = require('util'); const readdir = promisify(require('fs').readdir); const Enmap = require('enmap'); const chalk = require('chalk'); -const DBL = require("dblapi.js"); const client = new Discord.Client(); try { -client.config = require('./config'); + client.config = require('./config'); } catch (err) { - console.log('Could not load config.js: \n', err); - process.exit(); -} - + console.log('Failed to load config.js:', err); + process.exit(); +}; try{ -client.version = require('./version.json'); + client.version = require('./version.json'); } catch (err) { - console.log('Could not load version.json: \n', err); - process.exit(); -} - + console.log('Failed to load version.json:', err); + process.exit(); +}; try{ -client.logger = require('./src/modules/Logger'); + client.logger = require('./src/modules/Logger'); } catch (err) { - console.log('Could not load Logger.js: \n', err); - process.exit(); -} - -try{ -require("./src/modules/functions")(client); -} catch (err) { - console.log('Could not load functions.js: \n', err); - process.exit(); -} - -try{ + console.log('Failed to load Logger.js:', err); + process.exit(); +}; client.logger.setClient(client); + +try{ + require("./src/modules/functions")(client); } catch (err) { - console.log('Logger failed to initialize: \n', err); - process.exit(1); -} + console.log('Failed to load functions.js:', err); + process.exit(); +}; if(process.env['USER'] != 'container') { client.devmode = true; } else { client.devmode = false; - if(client.config.dblkey.length == 0) { + if(client.config.dblkey.length > 0) { + const DBL = require("dblapi.js"); const dblapi = new DBL(client.config.dblkey, client); - } -} + }; +}; -try{ client.commands = new Enmap(); -} catch (err) { - console.log('Failed to create the commands database: \n', err); - process.exit(); -} - -try{ client.aliases = new Enmap(); -} catch (err) { - console.log('Failed to create the aliases database: \n', err); - process.exit(); -} - -try{ client.settings = new Enmap({name: 'settings'}); -} catch (err) { - console.log('Failed to initialize the settings database: \n', err); - process.exit(); -} -try{ -client.blacklist = new Enmap({name: 'blacklist'}); -} catch (err) { - console.log('Failed to initialize the blacklist database: \n', err); - process.exit(1); -} - -try{ const init = async () => { const cmdFiles = await readdir("./src/commands/"); client.logger.info(`Loading ${cmdFiles.length} commands.`); @@ -103,30 +74,17 @@ const init = async () => { client.on(eventName, event.bind(null, client)); }); - try{ client.levelCache = {}; for (let i = 0; i < client.config.permLevels.length; i++) { const thisLevel = client.config.permLevels[i]; client.levelCache[thisLevel.name] = thisLevel.level; }; -} catch (err) { - console.log('Level cache failed to initialize: \n', err); - process.exit(); -} - try{ if(client.devmode === true) { client.login(client.config.devtoken); } else { client.login(client.config.token); }; -} catch (err) { - console.log('Could not login to Discord: \n', err); - process.exit(1); -} }; -init(); -} catch (err) { - console.log('Initialization failed: \n', err); - process.exit(1); -} + +init(); \ No newline at end of file diff --git a/package.json b/package.json index 901ffbf..4109849 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "dependencies": { "@discordjs/opus": "^0.1.0", - "better-sqlite3": "^5.4.1", + "better-sqlite3": "^5.4.3", "chalk": "^3.0.0", "dblapi.js": "^2.3.1", "discord.js": "^12.0.2", @@ -13,16 +13,17 @@ "garfield": "^1.1.2", "get-youtube-id": "^1.0.1", "hastebin-gen": "^2.0.5", - "is-url": "^1.2.4", "moment": "^2.24.0", "moment-duration-format": "^2.3.2", + "nekos.life": "^2.0.5", + "node-fetch": "^2.6.0", + "openweather-apis": "^4.2.0", "prism-media": "^1.2.1", "randomcolor": "^0.5.4", "relevant-urban": "^2.0.0", "request": "^2.88.2", + "to-zalgo": "^1.0.1", "urban": "^0.3.2", - "url-unshort": "^5.0.0", - "url-unshorten": "^1.0.6", "weather-js": "^2.0.0", "youtube-info": "^1.3.2", "ytdl-core-discord": "^1.1.0" diff --git a/src/commands/about.js b/src/commands/about.js index ad1666b..2049bfa 100644 --- a/src/commands/about.js +++ b/src/commands/about.js @@ -26,9 +26,9 @@ exports.run = (client, message) => { } embed = new Discord.MessageEmbed(); - embed.setTitle(`Woomy`); embed.setColor(client.embedColour(message)); embed.setThumbnail(client.user.avatarURL({format: "png", dynamic: true, size: 2048})) + embed.setTitle("About Woomy") embed.addField( "General:", `• users: \`${client.users.cache.size}\`\n• channels: \`${client.channels.cache.size}\`\n• servers: \`${client.guilds.cache.size}\`\n• commands: \`${client.commands.size}\`\n• uptime: \`${duration}\``,true ); diff --git a/src/commands/cat.js b/src/commands/cat.js new file mode 100644 index 0000000..afd627f --- /dev/null +++ b/src/commands/cat.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.meow().then((json) => { + message.channel.send(json.url) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("cat.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "cat", + category: "Image", + description: "Sends you cat pics.", + usage: "cat" +}; diff --git a/src/commands/catfact.js b/src/commands/catfact.js index 9fef875..a58aae4 100644 --- a/src/commands/catfact.js +++ b/src/commands/catfact.js @@ -1,14 +1,12 @@ -const request = require("request"); - +const fetch = require("node-fetch") exports.run = async (bot, message, args) => { message.channel.startTyping(); try{ - request({ uri: "https://catfact.ninja/facts", json: true }, (error, response, body) => { - message.channel.send(`**Did you know?**\n ${body.data[0].fact}`); - message.channel.stopTyping(); - }); + fetch('https://catfact.ninja/facts') + .then(res => res.json()) + .then(json => message.channel.send(`__**Did you know?**__\n${json.data[0].fact}`)) } catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`); message.channel.stopTyping(); }; }; diff --git a/src/commands/flip.js b/src/commands/coinflip.js similarity index 90% rename from src/commands/flip.js rename to src/commands/coinflip.js index 99ba778..418a996 100644 --- a/src/commands/flip.js +++ b/src/commands/coinflip.js @@ -22,14 +22,14 @@ exports.run = (client, message, args) => { exports.conf = { enabled: true, guildOnly: false, - aliases: [], + aliases: ["flip"], permLevel: "User", requiredPerms: [] }; exports.help = { - name: "flip", + name: "coinflip", category: "Fun", description: "Flips a coin!", - usage: "flip [heads/tails]" + usage: "coinflip [heads/tails]" }; diff --git a/src/commands/credits.js b/src/commands/credits.js index b3f8516..5eb48ce 100644 --- a/src/commands/credits.js +++ b/src/commands/credits.js @@ -1,6 +1,6 @@ exports.run = async (client, message, args) => { message.channel.send( - `**Credits:**\n• \`mudkipscience#8904\` and \`FLGX#9896\`for developing the bot\n• \`An Idiots Guide\` for the Guidebot bot base\n• \`dellannie#6057\` for helping with the music commands\n• \`TheCakeChicken#9088\` and \`Tina the Cyclops girl#0064\` for helping me not suck at coding\n• \`AirVentTrent\` for the icon, find him on Instagram` + `__**Credits:**__\n• \`mudkipscience#8904\`, \`FLGX#9896\` and \`TheCakeChicken#9088\` for developing the bot\n• \`An Idiots Guide\` for the Guidebot bot base\n• \`Tina the Cyclops girl#0064\` for helping me not suck at coding\n• \`AirVentTrent\` for the icon, find him on Instagram\n• \`Terryiscool160\` for contributing to Woomy.` ); }; @@ -14,7 +14,7 @@ exports.conf = { exports.help = { name: "credits", - category: "Miscellaneous", + category: "Utility", description: "Cool people", usage: "credits" }; diff --git a/src/commands/creeper.js b/src/commands/creeper.js new file mode 100644 index 0000000..80ac90b --- /dev/null +++ b/src/commands/creeper.js @@ -0,0 +1,45 @@ + +const lyric = require('../../resources/other/lyrics.json') +exports.run = async (client, message, args, level) => { + var lyrics = lyric.creeper; + + var runtop = true; + var runbottom = false; + for(var br = 0; br < lyrics.length; br++) { + { + if (runtop === true) { + var response = await client.awaitReply(message, lyrics[br]); + runbottom = false; + }; + + if (runbottom === true) { + if (response !== lyrics[br]) { + return message.channel.send("Those aren't the lyrics!") + } + runtop = false + }; + } if (runtop === true) { + runtop = false + runbottom = true + } else if (runbottom === true) { + runtop = true + runbottom = false + } + } + message.channel.send("What a lovely duet!") +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "creeper", + category: "Fun", + description: "Aww man", + usage: "creeper" +}; diff --git a/src/commands/cuddle.js b/src/commands/cuddle.js new file mode 100644 index 0000000..63263ae --- /dev/null +++ b/src/commands/cuddle.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to cuddle! Usage: \`${client.commands.get(`cuddle`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.cuddle().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** cuddled **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("cuddle.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "cuddle", + category: "Action", + description: "cuddle someone!", + usage: "cuddle [@user/user] (you can cuddle as many people as you want!)" +}; diff --git a/src/commands/dice.js b/src/commands/dice.js index 80ac90b..be9edcf 100644 --- a/src/commands/dice.js +++ b/src/commands/dice.js @@ -1,45 +1,27 @@ - -const lyric = require('../../resources/other/lyrics.json') -exports.run = async (client, message, args, level) => { - var lyrics = lyric.creeper; - - var runtop = true; - var runbottom = false; - for(var br = 0; br < lyrics.length; br++) { - { - if (runtop === true) { - var response = await client.awaitReply(message, lyrics[br]); - runbottom = false; - }; - - if (runbottom === true) { - if (response !== lyrics[br]) { - return message.channel.send("Those aren't the lyrics!") +exports.run = async (bot, message, args) => { + if (args.length === 0) { + message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); + } else { + if (args[0].match(/^\d+$/)) { + message.channel.send(`🎲 You rolled a ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}!`); + } else { + message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); } - runtop = false - }; - } if (runtop === true) { - runtop = false - runbottom = true - } else if (runbottom === true) { - runtop = true - runbottom = false - } - } - message.channel.send("What a lovely duet!") -}; - -exports.conf = { - enabled: true, - guildOnly: false, - aliases: [], - permLevel: "User", - requiredPerms: [] -}; - -exports.help = { - name: "creeper", - category: "Fun", - description: "Aww man", - usage: "creeper" -}; + } + }; + + exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["diceroll", "roll"], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "dice", + category: "Fun", + description: "Rolls a dice.", + usage: "dice " + }; + diff --git a/src/commands/diceroll.js b/src/commands/diceroll.js deleted file mode 100644 index 65900c8..0000000 --- a/src/commands/diceroll.js +++ /dev/null @@ -1,27 +0,0 @@ -exports.run = async (bot, message, args) => { - if (args.length === 0) { - message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); - } else { - if (args[0].match(/^\d+$/)) { - message.channel.send(`🎲 You rolled a ${Array.from(Array(parseInt(args[0])).keys()).random() + 1}!`); - } else { - message.channel.send(`🎲 You rolled a ${Array.from(Array(6).keys()).random() + 1}!`); - } - } - }; - - exports.conf = { - enabled: true, - guildOnly: false, - aliases: ["diceroll"], - permLevel: "User", - requiredPerms: [] - }; - - exports.help = { - name: "dice", - category: "Fun", - description: "Rolls a dice.", - usage: "dice **OR** dice " - }; - diff --git a/src/commands/dog.js b/src/commands/dog.js new file mode 100644 index 0000000..39ce25c --- /dev/null +++ b/src/commands/dog.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.woof().then((json) => { + message.channel.send(json.url) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("dog.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "dog", + category: "Image", + description: "Sends you dog pics.", + usage: "dog" +}; diff --git a/src/commands/dogfact.js b/src/commands/dogfact.js index 31d1639..d0b80ed 100644 --- a/src/commands/dogfact.js +++ b/src/commands/dogfact.js @@ -1,16 +1,15 @@ -const request = require("request"); - +const fetch = require("node-fetch"); exports.run = async (bot, message, args) => { message.channel.startTyping(); try{ - request({ uri: "https://dog-api.kinduff.com/api/facts", json: true }, (error, response, body) => { - message.channel.send(`**Did you know?**\n ${body.facts[0]}`); + fetch('https://dog-api.kinduff.com/api/facts') + .then(res => res.json()) + .then(json => message.channel.send(`__**Did you know?**__\n ${json.facts[0]}`)); message.channel.stopTyping(); - }); -} catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); - message.channel.stopTyping(); -}; + } catch(err) { + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`); + message.channel.stopTyping(); + }; }; exports.conf = { diff --git a/src/commands/emojify.js b/src/commands/emojify.js index 058faa3..46dfa35 100644 --- a/src/commands/emojify.js +++ b/src/commands/emojify.js @@ -34,7 +34,7 @@ exports.run = (client, message, args) => { if(emojified.length > 2000) { return message.channel.send("<:error:466995152976871434> The emojified message exceeds 2000 characters.") - } + }; message.channel.send(emojified); }; diff --git a/src/commands/fact.js b/src/commands/fact.js new file mode 100644 index 0000000..0e351a6 --- /dev/null +++ b/src/commands/fact.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.fact().then((json) => { + message.channel.send("__**Did you know?**__\n" + json.fact + "."); + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("fact.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["randomfact"], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "fact", + category: "Fun", + description: "Sends you a random fact.", + usage: "fact" +}; diff --git a/src/commands/feed.js b/src/commands/feed.js new file mode 100644 index 0000000..9749f45 --- /dev/null +++ b/src/commands/feed.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to feed! Usage: \`${client.commands.get(`feed`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.feed().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** fed **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("feed.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "feed", + category: "Action", + description: "feed someone!", + usage: "feed [@user/user] (you can feed as many people as you want!)" +}; diff --git a/src/commands/feedback.js b/src/commands/feedback.js index 9f4e436..6b4512b 100644 --- a/src/commands/feedback.js +++ b/src/commands/feedback.js @@ -22,7 +22,7 @@ exports.conf = { exports.help = { name: "feedback", - category: "Miscellaneous", + category: "Utility", description: "Send feedback to my developer.", usage: "feedback [message]" }; diff --git a/src/commands/foxgirl.js b/src/commands/foxgirl.js new file mode 100644 index 0000000..f3f3312 --- /dev/null +++ b/src/commands/foxgirl.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.foxGirl().then((json) => { + message.channel.send(json.url) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("foxgirl.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "foxgirl", + category: "Image", + description: "Sends you pictures of fox girls.", + usage: "foxgirl" +}; diff --git a/src/commands/help.js b/src/commands/help.js index 0dd8acf..5c07963 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -3,7 +3,7 @@ exports.run = (client, message, args, level) => { embed.setColor(client.embedColour(message)); var ran = false; - var output = "```"; + var output = ""; var commands = 0; var prefix; var currentCategory; @@ -15,7 +15,7 @@ exports.run = (client, message, args, level) => { }; if(!args[0]) { - embed.setTitle(`Commands [${client.commands.size}]`); + embed.setTitle(`Command list`); embed.setDescription(`⁣For more information on a specific command use \`${prefix}help \`\nFor the full command list use \`${prefix}help all\`\n`); const myCommands = message.guild ? client.commands.filter( @@ -35,24 +35,20 @@ exports.run = (client, message, args, level) => { ); sorted.forEach( c => { - const cat = c.help.category.toProperCase(); + const cat = c.help.category; if (currentCategory !== cat) { if(ran == true) { - output = output.slice(0, -2) + "```"; embed.addField(currentCategory + ` [${commands}]`, output) - output = "```"; + output = ""; commands = 0; } currentCategory = cat; ran = true } - output += `${prefix}${c.help.name}, `; + output += `\`${c.help.name}\` `; commands = commands + 1; }); - output = output.slice(0, -2); - output = output + "```" - embed.addField(currentCategory + ` [${commands}]`, output); embed.addField( @@ -72,7 +68,7 @@ exports.run = (client, message, args, level) => { }; if(args[0].toLowerCase() == "all") { - embed.setTitle(`Commands [${client.commands.size}]`); + embed.setTitle(`Command list`); embed.setDescription(`⁣For more information on a specific command use \`${prefix}help \`\nFor the full command list use \`${prefix}help all\`\n`); const myCommands = client.commands @@ -88,22 +84,21 @@ exports.run = (client, message, args, level) => { ); sorted.forEach( c => { - const cat = c.help.category.toProperCase(); + const cat = c.help.category; if (currentCategory !== cat) { if(ran == true) { - output = output.slice(0, -2) + "```"; embed.addField(currentCategory + ` [${commands}]`, output) - output = "```"; + output = ""; commands = 0; } currentCategory = cat; ran = true } - output += `${prefix}${c.help.name}, `; + output += `\`${c.help.name}\` `; commands = commands + 1; }); - output = output.slice(0, -2) + "```"; + embed.addField(currentCategory + ` [${commands}]`, output); embed.addField( diff --git a/src/commands/hug.js b/src/commands/hug.js new file mode 100644 index 0000000..30ef214 --- /dev/null +++ b/src/commands/hug.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to hug! Usage: \`${client.commands.get(`hug`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.hug().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** hugged **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("hug.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "hug", + category: "Action", + description: "Hug someone!", + usage: "hug [@user/user] (you can hug as many people as you want!)" +}; diff --git a/src/commands/identity.js b/src/commands/identity.js index 22e8693..b7f3809 100644 --- a/src/commands/identity.js +++ b/src/commands/identity.js @@ -16,7 +16,7 @@ exports.run = async (client, message, args) => { if(!output) { return message.channel.send("<:error:466995152976871434> No results for that query."); }; - return message.channel.send(`__**${output.name}**__\n${output.description}`); + return message.channel.send(`__**${output.name.toProperCase()}**__\n${output.description}`); }; }; diff --git a/src/commands/inspirobot.js b/src/commands/inspirobot.js index 5ba4e0a..17a028f 100644 --- a/src/commands/inspirobot.js +++ b/src/commands/inspirobot.js @@ -1,20 +1,15 @@ -const request = require('request') +const fetch = require("node-fetch") exports.run = async (client, message) => { message.channel.startTyping(); - request({ - url: "http://inspirobot.me/api?generate=true" - }, - function(error, res, body) { - if(body.length > 0) { - message.channel.send({ - files: [new Discord.MessageAttachment(body)] - }); - message.channel.stopTyping(); - } else { - message.channel.send('<:error:466995152976871434> API error, please retry.') - message.channel.stopTyping(); - }; - }); + try { + fetch('http://inspirobot.me/api?generate=true') + .then(res => res.text()) + .then(body => message.channel.send({files: [new Discord.MessageAttachment(body)]})); + message.channel.stopTyping(); + } catch (err) { + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; }; exports.conf = { diff --git a/src/commands/kemonomimi.js b/src/commands/kemonomimi.js new file mode 100644 index 0000000..3c4b70e --- /dev/null +++ b/src/commands/kemonomimi.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.kemonomimi().then((json) => { + message.channel.send(json.url) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("kemonomimi.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "kemonomimi", + category: "Image", + description: "Sends you pictures of people with animal characteristics.", + usage: "kemonomimi" +}; diff --git a/src/commands/kiss.js b/src/commands/kiss.js new file mode 100644 index 0000000..495ee62 --- /dev/null +++ b/src/commands/kiss.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to kiss! Usage: \`${client.commands.get(`kiss`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.kiss().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** kissed **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("kiss.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "kiss", + category: "Action", + description: "Kiss someone!", + usage: "kiss [@user/user] (you can kiss as many people as you want!)" +}; diff --git a/src/commands/lizard.js b/src/commands/lizard.js new file mode 100644 index 0000000..f476704 --- /dev/null +++ b/src/commands/lizard.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.lizard().then((json) => { + message.channel.send(json.url) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("lizard.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "lizard", + category: "Image", + description: "Sends pictures of lizards.", + usage: "lizard" +}; diff --git a/src/commands/neko.js b/src/commands/neko.js new file mode 100644 index 0000000..7ce0d6b --- /dev/null +++ b/src/commands/neko.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.neko().then((json) => { + message.channel.send(json.url); + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("neko.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["catgirl"], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "neko", + category: "Image", + description: "Sends you pictures of catgirls.", + usage: "neko" +}; diff --git a/src/commands/nekogif.js b/src/commands/nekogif.js new file mode 100644 index 0000000..0df6917 --- /dev/null +++ b/src/commands/nekogif.js @@ -0,0 +1,30 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.nekoGif().then((json) => { + message.channel.send(json.url); + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("nekogif.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["catgirlgif"], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "nekogif", + category: "Image", + description: "Sends you gifs of catgirls.", + usage: "nekogif" +}; diff --git a/src/commands/owoify.js b/src/commands/owoify.js index ae8b9a5..9587a6f 100644 --- a/src/commands/owoify.js +++ b/src/commands/owoify.js @@ -13,8 +13,8 @@ exports.run = (client, message, args) => { owoified = owoified.replace(/!+/g, ' ' + faces[~~(Math.random() * faces.length)] + ' ') if(owoified.length > 2000) { - return message.channel.send("<:error:466995152976871434> The owoified message exceeds 2000 characters.") - } + owoified = owoified.slice(0, -Math.abs(owoified.length - 2000)) + }; message.channel.send(owoified) }; diff --git a/src/commands/pat.js b/src/commands/pat.js new file mode 100644 index 0000000..fee469b --- /dev/null +++ b/src/commands/pat.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to pat! Usage: \`${client.commands.get(`pat`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.pat().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** patted **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("pat.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: ["headpat"], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "pat", + category: "Action", + description: "pat someone!", + usage: "pat [@user/user] (you can pat as many people as you want!)" +}; diff --git a/src/commands/poke.js b/src/commands/poke.js new file mode 100644 index 0000000..07c48bc --- /dev/null +++ b/src/commands/poke.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to poke! Usage: \`${client.commands.get(`poke`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.poke().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** poked **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("poke.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "poke", + category: "Action", + description: "poke someone!", + usage: "poke [@user/user] (you can poke as many people as you want!)" +}; diff --git a/src/commands/pronoun.js b/src/commands/pronoun.js index a535647..0d4b36a 100644 --- a/src/commands/pronoun.js +++ b/src/commands/pronoun.js @@ -5,7 +5,7 @@ exports.run = async (client, message, args) => { for (var key of Object.keys(pronouns)) { output += `${key}, ` }; - return message.channel.send(`__**Pronouns**__\n${output.slice(0, -2)}`); + return message.channel.send(`__**Pronouns:**__\n${output.slice(0, -2)}`); } else { if(args.join(" ").toLowerCase() == "attack helicopter" || args.join(" ").toLowerCase() == "apache attack helicopter" || args.join(" ").toLowerCase() == "apache") { return message.channel.send({ @@ -16,7 +16,7 @@ exports.run = async (client, message, args) => { if(!output) { return message.channel.send("<:error:466995152976871434> No results for that query."); }; - return message.channel.send(`__**Example sentences using ${output.name}**__\n${output.examples}`); + return message.channel.send(`__**Example sentences using ${output.name}:**__\n${output.examples}`); }; }; diff --git a/src/commands/roleinfo.js b/src/commands/roleinfo.js index e6c95a4..10d8c4d 100644 --- a/src/commands/roleinfo.js +++ b/src/commands/roleinfo.js @@ -52,7 +52,6 @@ exports.run = async (client, message, args, level) => { var embed = new Discord.MessageEmbed(); embed.setColor(role.color); embed.setTitle(role.name); - embed.setThumbnail("https://api.alexflipnote.xyz/colour/image/" + role.hexColor.replace("#", "")); embed.setDescription( `• **ID:** ${role.id}\n• **Hex:** ${role.hexColor}\n• **Members:** ${role.members.size}\n• **Position:** ${role.position}\n• **Hoisted:** ${role.hoist}` ); diff --git a/src/commands/sexuality.js b/src/commands/sexuality.js index 8507dac..c41930b 100644 --- a/src/commands/sexuality.js +++ b/src/commands/sexuality.js @@ -5,7 +5,7 @@ exports.run = async (client, message, args) => { for (var key of Object.keys(sexualities)) { output += `${key}, ` }; - return message.channel.send(`__**sexualities**__\n${output.slice(0, -2)}`); + return message.channel.send(`__**Sexualities:**__\n${output.slice(0, -2)}`); } else { if(args.join(" ").toLowerCase() == "attack helicopter" || args.join(" ").toLowerCase() == "apache attack helicopter" || args.join(" ").toLowerCase() == "apache") { return message.channel.send({ @@ -16,7 +16,7 @@ exports.run = async (client, message, args) => { if(!output) { return message.channel.send("<:error:466995152976871434> No results for that query."); }; - return message.channel.send(`__**${output.name}**__\n${output.description}`); + return message.channel.send(`__**${output.name.toProperCase()}:**__\n${output.description}`); }; }; diff --git a/src/commands/ship.js b/src/commands/ship.js index b11a988..3850d87 100644 --- a/src/commands/ship.js +++ b/src/commands/ship.js @@ -31,7 +31,7 @@ exports.run = async (client, message, args) => { name1 = args[1]; }; - shipName = name.substring(0, client.intBetween(1,name.length))+name1.substring(client.intBetween(0,name1.length)); + shipName = name.substr(0, client.intBetween(1,name.length))+name1.substr(client.intBetween(0,name1.length)); message.channel.send(`__**Ship Generator:**__\n${hearts.random()} Ship Name: \`${shipName}\`\n${hearts.random()} Compatibility rating: \`${rating}%\``) }; diff --git a/src/commands/slap.js b/src/commands/slap.js new file mode 100644 index 0000000..2e5189c --- /dev/null +++ b/src/commands/slap.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to slap! Usage: \`${client.commands.get(`kiss`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.slap().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** slapped **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("slap.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "slap", + category: "Action", + description: "Slap someone >:3", + usage: "slap [@user/user] (you can slap as many people as you want!)" +}; diff --git a/src/commands/smug.js b/src/commands/smug.js new file mode 100644 index 0000000..011f2bd --- /dev/null +++ b/src/commands/smug.js @@ -0,0 +1,33 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message) => { + message.channel.startTyping(); + try { + sfw.smug().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("smug.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "smug", + category: "Action", + description: "Sends a smug gif.", + usage: "smug" +}; diff --git a/src/commands/spoilerise.js b/src/commands/spoilerise.js new file mode 100644 index 0000000..25ab221 --- /dev/null +++ b/src/commands/spoilerise.js @@ -0,0 +1,28 @@ +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't provide any text! Usage: \`${client.commands.get(`spoiler`).help.usage}\``) + }; + + var output = `||${[...message.cleanContent.substring(9)].join("||||")}||`; + + if(output.length > 2000) { + output = output.slice(0, -Math.abs(output.length - 2000)) + }; + + message.channel.send(output) +}; + +exports.conf = { + enabled: true, + guildOnly: false, + aliases: ["spoilerize", "spoiler"], + permLevel: "User", + requiredPerms: [] +}; + +exports.help = { + name: "spoilerise", + category: "Fun", + description: "Spoilers every letter in the provided text.", + usage: "spoiler [text]" +}; diff --git a/src/commands/support.js b/src/commands/support.js index 8fad6b2..c15de88 100644 --- a/src/commands/support.js +++ b/src/commands/support.js @@ -12,7 +12,7 @@ exports.conf = { exports.help = { name: "support", - category: "utility", + category: "Utility", description: "Sends a link to Woomy's support/development server.", usage: "support" }; diff --git a/src/commands/tickle.js b/src/commands/tickle.js new file mode 100644 index 0000000..e75a771 --- /dev/null +++ b/src/commands/tickle.js @@ -0,0 +1,69 @@ +const API = require('nekos.life'); +const {sfw} = new API(); +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't say who you wanted to tickle! Usage: \`${client.commands.get(`tickle`).help.usage}\``) + }; + + var people = ""; + + for (var i = 0; i < args.length; i++) { + var user = client.getUserFromMention(args[i]) + if (user) { + user = message.guild.members.cache.get(user.id).displayName; + } else { + users = client.searchForMembers(message.guild, args[i]); + if (users.length > 1) + return message.channel.send( + "<:error:466995152976871434> Found multiple users for `" + args[i] + "`, Please be more specific or mention the user instead." + ); + else if (users.length == 0) + return message.channel.send( + "<:error:466995152976871434> That user doesn't seem to exist. Try again!" + ); + user = users[0].displayName; + }; + if(i+1 == args.length && args.length > 1) { + people += `**and** ${user}!` + } else if(args.length < 2) { + people += `${user}!`; + } else if(args.length == 2 && i == 0) { + people += `${user} `; + } else { + people += `${user}, `; + }; + }; + + + + message.channel.startTyping(); + try { + sfw.tickle().then((json) => { + embed = new Discord.MessageEmbed(); + embed.setImage(json.url) + embed.setColor(client.embedColour(message)); + embed.setDescription(`**${message.guild.members.cache.get(message.author.id).displayName}** tickled **${people}**`) + message.channel.send(embed) + message.channel.stopTyping(); + }); + } catch (err) { + client.logger.error("tickle.js: " + err); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`) + message.channel.stopTyping(); + }; +}; + +exports.conf = { + enabled: true, + guildOnly: true, + aliases: [], + permLevel: "User", + requiredPerms: ["EMBED_LINKS"] +}; + +exports.help = { + name: "tickle", + category: "Action", + description: "Tickle someone!", + usage: "tickle [@user/user] (you can tickle as many people as you want!)" +}; diff --git a/src/commands/weather.js b/src/commands/weather.js index 4af8b86..ef01bc8 100644 --- a/src/commands/weather.js +++ b/src/commands/weather.js @@ -5,46 +5,47 @@ exports.run = async (client, message, args, error) => { `<:error:466995152976871434> You didn't give me a location. Usage: \`${client.commands.get(`weather`).help.usage}\`` ); }; - - if(args.join(" ").toLowerCase() == "antarctica") { - return; - } message.channel.startTyping(); - - weather.find({search: args.join(" "), degreeType: 'C'}, function(err, result) { - if(err) return client.logger.log(`weather.js error: ${JSON.stringify(error)}`, "error") - if(result.length < 2 || !result) { + + try { + weather.find({search: args.join(" "), degreeType: 'C'}, function(err, result) { + if(err) return message.channel.send(`<:error:466995152976871434> API error: \`${error}\``) + if(result.length < 2 || !result) { + message.channel.stopTyping(); + return message.channel.send("<:error:466995152976871434> City not found!"); + }; + + var location = result[0].location; + var current = result[0].current; + + var warning = (`${location.alert}` || "No warnings"); + + var embedColour; + if (current.temperature < 0) { + embedColour = "#addeff"; + }else if (current.temperature < 20) { + embedColour = "#4fb8ff"; + }else if (current.temperature < 26) { + embedColour = "#ffea4f"; + }else if (current.temperature < 31) { + embedColour = "#ffa14f" + } else { + embedColour = "#ff614f" + }; + + embed = new Discord.MessageEmbed(); + embed.setAuthor(`Weather for ${location.name}:`) + embed.setDescription(`• **Condition:** ${current.skytext}\n• **Temperature:** ${current.temperature}°C\n• **Feels like:** ${current.feelslike}°C\n• **Humidity:** ${current.humidity}%\n• **Wind:** ${current.winddisplay}\n• **Warnings:** ${warning}`) + embed.setThumbnail(current.imageUrl) + embed.setFooter(`Last updated at ${current.observationtime} ${current.date}`) + embed.setColor(embedColour) message.channel.stopTyping(); - return message.channel.send("<:error:466995152976871434> City not found!"); - }; - - var location = result[0].location; - var current = result[0].current; - - var warning = (`${location.alert}` || "No warnings"); - - var embedColour; - if (current.temperature < 0) { - embedColour = "#addeff"; - }else if (current.temperature < 20) { - embedColour = "#4fb8ff"; - }else if (current.temperature < 26) { - embedColour = "#ffea4f"; - }else if (current.temperature < 31) { - embedColour = "#ffa14f" - } else { - embedColour = "#ff614f" - }; - - embed = new Discord.MessageEmbed(); - embed.addField(`Weather for ${location.name}:`, `**Condition:** ${current.skytext}\n**Temperature:** ${current.temperature}C°\n**Feels like:** ${current.feelslike}C°\n**Humidity:** ${current.humidity}%\n**Wind:** ${current.winddisplay}\n**Warnings:** ${warning}`) - embed.setThumbnail(current.imageUrl) - embed.setFooter(`Last updated at ${current.observationtime} ${current.date}`) - embed.setColor(embedColour) - message.channel.stopTyping(); - message.channel.send(embed) - }); + message.channel.send(embed) + }); + } catch(err) { + return message.channel.send(`<:error:466995152976871434> API error: \`${err}\``) + }; }; exports.conf = { diff --git a/src/commands/yoda.js b/src/commands/yoda.js index 8b61784..496b929 100644 --- a/src/commands/yoda.js +++ b/src/commands/yoda.js @@ -1,34 +1,33 @@ -const request = require('request') +const fetch = require("node-fetch") exports.run = async (client, message, args) => { const speech = args.join(' '); if (!speech) { return message.channel.send(`<:error:466995152976871434> Please include text for me to convert to yodish. Yes.`) }; - message.channel.startTyping(); try{ - request({ uri: `http://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(speech.toLowerCase())}`, json: true }, (error, response, body) => { - message.channel.send(body.yodish); - message.channel.stopTyping(); - }); + fetch(`http://yoda-api.appspot.com/api/v1/yodish?text=${encodeURIComponent(speech.toLowerCase())}`) + .then(res => res.json()) + .then(json => message.channel.send(json.yodish)); + message.channel.stopTyping(); } catch(err) { - message.channel.send(`<:error:466995152976871434> API error: ${err}`); + message.channel.send(`<:error:466995152976871434> An error has occurred: ${err}`); message.channel.stopTyping(); }; }; exports.conf = { - enabled: true, - guildOnly: false, - aliases: ["yoda","yodasay"], - permLevel: "User", - requiredPerms: [] - }; - + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] +}; + exports.help = { - name: "yodish", - category: "Fun", - description: "Turns any text you input into yodish. Yes.", - usage: "yodish " - }; \ No newline at end of file + name: "yoda", + category: "Fun", + description: "Turns any text you input into yodish. Yes.", + usage: "yoda " +}; \ No newline at end of file diff --git a/src/commands/zalgo.js b/src/commands/zalgo.js new file mode 100644 index 0000000..bf2e082 --- /dev/null +++ b/src/commands/zalgo.js @@ -0,0 +1,30 @@ +const zalgo = require("to-zalgo") +exports.run = async (client, message, args) => { + if(!args[0]) { + return message.channel.send(`<:error:466995152976871434> You didn't provide any text! Usage: \`${client.commands.get(`zalgo`).help.usage}\``) + }; + + var output = zalgo(args.join(" ")) + + if(output.length > 2000) { + output = output.slice(0, -Math.abs(output.length - 2000)) + }; + + message.channel.send(output) + }; + + exports.conf = { + enabled: true, + guildOnly: false, + aliases: [], + permLevel: "User", + requiredPerms: [] + }; + + exports.help = { + name: "zalgo", + category: "Fun", + description: "Spoilers every letter in the provided text.", + usage: "zalgo [text]" + }; + \ No newline at end of file diff --git a/src/events/ready.js b/src/events/ready.js index 4a3ce44..f37a7d9 100644 --- a/src/events/ready.js +++ b/src/events/ready.js @@ -8,11 +8,15 @@ module.exports = client => { client.logger.log(`Connected to Discord as ${client.user.tag} | v${client.version.number}`, 'ready'); - let channel; - let channel1; + let channel, channel1; - try { channel = client.guilds.cache.get('410990517841690625').channels.cache.get('570963998342643732'); } catch(err) {}; - try { channel1 = client.guilds.cache.get('410990517841690625').channels.cache.get('570963481189154822'); } catch(err) {}; + try { + channel = client.guilds.cache.get('410990517841690625').channels.cache.get('570963998342643732'); + } catch(err) {}; + + try { + channel1 = client.guilds.cache.get('410990517841690625').channels.cache.get('570963481189154822'); + } catch(err) {}; if(client.devmode == true) { client.logger.warn("Running in development mode.") @@ -21,13 +25,16 @@ module.exports = client => { prefix = client.config.defaultSettings.prefix; channel.send(`\`${timestamp}\`: Ready event fired! Connected to ${client.users.cache.size} users in ${client.guilds.cache.size} guilds.`); channel1.send(`\`${timestamp}\`: **Ready event fired**`); - } + }; let randomActivity = activityArray.random(); client.user.setActivity(`${prefix + randomActivity} | v${client.version.number}`, {type: "PLAYING"}); + setInterval(() => { randomActivity = activityArray.random(); - if(client.lockActivity == false) client.user.setActivity(`${prefix + randomActivity} | v${client.version.number}`, {type: "PLAYING"}); + if(client.lockActivity == false) { + client.user.setActivity(`${prefix + randomActivity} | v${client.version.number}`, {type: "PLAYING"}); + }; }, 30000); }; diff --git a/src/modules/functions.js b/src/modules/functions.js index f51a34d..a30dd4b 100644 --- a/src/modules/functions.js +++ b/src/modules/functions.js @@ -1,7 +1,7 @@ const ytdl = require('ytdl-core-discord'); const youtubeInfo = require('youtube-info'); const getYoutubeId = require('get-youtube-id'); -const request = require('request'); +const fetch = require('node-fetch'); module.exports = client => { // Permission level function @@ -160,14 +160,17 @@ module.exports = client => { { return new Promise(function(resolve, reject) { - request("https://www.googleapis.com/youtube/v3/search?part=id&type=video&q=" + encodeURIComponent(query) + "&key=" + client.config.ytkey, function(error, response, body) - { - if(error) throw error; - - var json = JSON.parse(body); + try{ + fetch("https://www.googleapis.com/youtube/v3/search?part=id&type=video&q=" + encodeURIComponent(query) + "&key=" + client.config.ytkey) + .then(res => res.json()) + .then(json => { if(!json.items) { reject(); return; } resolve(json.items[0]); - }); + }); + } catch (err) { + client.logger.error("Music search err: ", err); + throw err; + }; }); } @@ -374,6 +377,6 @@ module.exports = client => { }); process.on("unhandledRejection", err => { - client.logger.error(`Unhandled rejection: ${err}`); + client.logger.error(`Unhandled rejection: ${err.stack}`); }); };