diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..6594a91 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 9 +} \ No newline at end of file diff --git a/bot.js b/bot.js index ef31b51..9fde210 100644 --- a/bot.js +++ b/bot.js @@ -3,10 +3,15 @@ const Discord = require('discord.js'); const chalk = require('chalk'); const ora = require('ora'); const mongoose = require('mongoose'); +const readline = require('readline'); + +const {SlashCommand} = require('./util/slash'); +const {SlashManager} = require('./util/slashmanager'); +const {SlashCommandBuilder} = require('@discordjs/builders'); const flags = Discord.Intents.FLAGS; -let fl = []; Object.keys(flags).forEach(flag => fl.push(flags[flag])) -const client = new Discord.Client({intents: fl, partials: ["CHANNEL", "REACTION", "MESSAGE"]}); +let fl = []; Object.keys(flags).forEach(flag => fl.push(flags[flag])); +let client = new Discord.Client({intents: fl, partials: ["CHANNEL", "REACTION", "MESSAGE"]}); client.misc = { savers: ['497598953206841375', '480535078150340609', '468903364533420074'], @@ -32,7 +37,8 @@ client.misc = { VCG: {}, activeVC: [] }, - loggers: {} + loggers: {}, + rl: readline.createInterface({input: process.stdin, output: process.stdout}) }; //const config = require('./config.js'); @@ -50,6 +56,31 @@ async function init() { client.misc.startupNoConnect = new Date(); client.config = auth; + /*client.slash = new SlashManager(client); + client.slash.setTestServer('691122844339404800').add(new SlashCommand('fortune', client, new SlashCommandBuilder() + .setName('fortune') + .setDescription("Get a totally accurate and well-thought-out answer to your life's troubles.") + .addStringOption(option => { + return option.setName("question") + .setDescription("Your existential crisis.") + .setRequired(true); + }) + .addBooleanOption(option => { + return option.setName("send") + .setDescription("Should I send the answer to the channel?"); + }), async (client, interaction) => {return await interaction.reply({embeds: [new Discord.MessageEmbed() + .setAuthor("8ball Question", interaction.user.id) + .setDescription("**Question:** " + interaction.options.getString('question') + "\n**Answer:** " + responses[Math.floor(Math.random() * responses.length)]) + .setColor("c375f0") + .setFooter(`Asked by ${interaction.guild ? interaction.member.displayName : interaction.user.username} | Natsuki`) + .setTimestamp()], + ephemeral: !interaction.options.getBoolean("send")});})).init(); + + client = client.slash.client; + + //client.slash.commands[0].registerToServer(client.slash.testServerId); + */ + let mloginsp = ora(chalk.magentaBright('Connecting to Mongo client...')).start(); let pmcc = new Date().getTime(); const config = client.config; @@ -57,22 +88,22 @@ async function init() { await mongoose.connect(`mongodb+srv://${config.database.user}:${config.database.password}@${config.database.cluster}.3jpp4.mongodb.net/test`, { useFindAndModify: false, useNewUrlParser: true, dbName: 'Natsuki-Main', useUnifiedTopology: true, useCreateIndex: true }).catch(e => { - let date = new Date; date = date.toString().slice(date.toString().search(":") - 2, date.toString().search(":") + 6); + let date = new Date(); date = date.toString().slice(date.toString().search(":") - 2, date.toString().search(":") + 6); console.error(`\n${chalk.red('[ERROR]')} >> ${chalk.yellow(`At [${date}] | Occurred while trying to connect to Mongo Cluster`)}`, e); mloginsp.stop(); mloginsp.clear(); }); mloginsp.stop(); mloginsp.clear(); console.log(`${chalk.green('[BOOT]')} >> ${chalk.greenBright(`Connected to Mongo Database in `)}${chalk.white(`${new Date().getTime() - pmcc}ms`)}`); } catch (e) { - let date = new Date; date = date.toString().slice(date.toString().search(":") - 2, date.toString().search(":") + 6); + let date = new Date(); date = date.toString().slice(date.toString().search(":") - 2, date.toString().search(":") + 6); console.error(`\n${chalk.red('[ERROR]')} >> ${chalk.yellow(`At [${date}] | Occurred while trying to connect to Mongo Cluster`)}`, e); mloginsp.stop(); mloginsp.clear(); } - ['commands', 'aliases'].forEach(x => client[x] = new Discord.Collection()); + ['commands', 'aliases', 'executables'].forEach(x => client[x] = new Discord.Collection()); client.responses = {triggers: [], commands: new Discord.Collection()}; - ['command', 'event', 'response'].forEach(x => require(`./handle/${x}`)(client)); + ['command', 'event', 'response', 'console'].forEach(x => require(`./handle/${x}`)(client)); client.developers = ["330547934951112705", "673477059904929802"]; client.utils = {}; @@ -83,6 +114,9 @@ async function init() { client.guildconfig.logs = new Map(); - await require('./util/wait')(5000).then(async () => {if (!client.misc.readied) {client.misc.forcedReady = true; await require('./events/ready')(client);}}); + await require('./util/wait')(5000); + if (!client.misc.readied) {client.misc.forcedReady = true; await require('./events/ready')(client);} + + require('./console')(client); } init().then(() => {}); \ No newline at end of file diff --git a/commands/anime/anime.js b/commands/anime/anime.js index 1ed2b3c..bb0c579 100644 --- a/commands/anime/anime.js +++ b/commands/anime/anime.js @@ -42,7 +42,7 @@ module.exports = { new Tag(['streams', 'streamat', 'sa'], 'streamAt', 'listAppend'), new Tag(['img', 'thumb', 'thumbnail', 'image']) ]).test(args.join(' ')); - + if (Object.keys(options).length) { let foptions = {}; let option; for (option of Object.keys(options)) { @@ -170,4 +170,4 @@ module.exports = { } catch {return message.channel.send("Hmm... there was some kind of error when I tried to submit that anime. Try again, and if it keeps not working, then go yell at my devs!");} } } -}; \ No newline at end of file +}; diff --git a/console.js b/console.js new file mode 100644 index 0000000..0fdfef2 --- /dev/null +++ b/console.js @@ -0,0 +1,23 @@ +const chalk = require('chalk'); +const readline = require('readline'); + +module.exports = (client) => { + console.log(`\n${chalk.green('[CONS]')} >> ${chalk.magentaBright(`Type `)}${chalk.white(`"help"`)} ${chalk.magentaBright("for a list of console commands.")}`); + + client.misc.rl.on("line", async (line) => { + if (!line.length) {return;} + + readline.moveCursor(process.stdout, 0, -1); + readline.clearLine(process.stdout, 1); + + console.log(""); + + const text = line; + const args = text.split(/\s+/gm); + const cmd = args.shift().toLowerCase(); + + const command = client.executables.get(cmd); + if (!command) {return console.log(`${chalk.yellow('[CONS]')} >> ${chalk.yellowBright(`Command `)}${chalk.white(`"${cmd}"`)} ${chalk.yellowBright("doesn't exist.")}`);} + await command.execute(client, text, args, cmd); + }); +}; \ No newline at end of file diff --git a/events/messageCreate.js b/events/messageCreate.js index d6bcbc2..95036c6 100644 --- a/events/messageCreate.js +++ b/events/messageCreate.js @@ -109,7 +109,7 @@ module.exports = async (client, message) => { } let trigger; for (trigger of client.responses.triggers) {if (await trigger[1](message, msg, args, cmd, prefix, mention, client)) {await client.responses.commands.get(trigger[0]).execute(message, msg, args, cmd, prefix, mention, client); break;}} } catch (e) { - let date = new Date; date = date.toString().slice(date.toString().search(":") - 2, date.toString().search(":") + 6); + let date = new Date(); date = date.toString().slice(date.toString().search(":") - 2, date.toString().search(":") + 6); console.error(`\n${chalk.red('[ERROR]')} >> ${chalk.yellow(`At [${date}] | In ${message.guild ? message.guild.name : `a DM with ${message.author.username}`}\n`)}`, e); } }; \ No newline at end of file diff --git a/events/ready.js b/events/ready.js index b6ee643..57d990d 100644 --- a/events/ready.js +++ b/events/ready.js @@ -108,7 +108,7 @@ module.exports = async client => { console.log(`${chalk.gray('\n[INFO]')} >> ${chalk.white(`This is restart #${botData.restarts}.`)}`); let cms = new Date().getTime(); - console.log(`${chalk.gray('\n[INFO]')} >> ${chalk.white(`Startup completed in ${cms - client.misc.startup.getTime() - client.misc.forcedReady ? 5000 : 0}ms (${cms - client.misc.startupNoConnect.getTime() - client.misc.forcedReady ? 5000 : 0}ms post-connect).`)}`); + console.log(`${chalk.gray('\n[INFO]')} >> ${chalk.white(`Startup completed in ${cms - client.misc.startup.getTime() - (client.misc.forcedReady ? 5000 : 0)}ms (${cms - client.misc.startupNoConnect.getTime() - (client.misc.forcedReady ? 5000 : 0)}ms post-connect).`)}`); await botData.save(); }; \ No newline at end of file diff --git a/executables/help.js b/executables/help.js new file mode 100644 index 0000000..78fa955 --- /dev/null +++ b/executables/help.js @@ -0,0 +1,28 @@ +const chalk = require('chalk'); + +const {Tag} = require('../util/tag'); +const {TagFilter} = require('../util/tagfilter'); + +module.exports = { + name: "help", + description: "Displays a list of usable commands.", + help: "Displays a list of usable commands.", + usage: "help [command]", + args: ['list'], + execute(client, text, args, cmd) { + const options = args.length ? new TagFilter([new Tag(['l', 'list'], 'list', 'toggle')]).test(args.join(" ")) : {}; + + const sp = ' >> '; + + if (args[0] || options.cmd) { + if (!client.executables.has(args[0].toLowerCase())) {return console.log(`${chalk.yellow('[CONS]')} >> ${chalk.yellowBright(`Command `)}${chalk.white(`"${ex.name}"`)} ${chalk.yellowBright("doesn't exist.")}`);} + const ex = client.executables.get(args[0]); + return console.log(`${chalk.gray('[CONS]')} >> [${chalk.blue(`HELP`)}] -> ${chalk.blueBright(ex.name)}\n\n${sp}<${chalk.hex('#b57124')(ex.name)}> - ${chalk.greenBright(ex.usage)}\n${sp}${ex.description} > ${chalk.gray(ex.args.length ? `-${ex.args.join(', -')}` : 'No args')}`); + } else { + let s = ''; + s += `${chalk.gray('[CONS]')} >> [${chalk.blue(`HELP`)}] -> ${chalk.blueBright(`Available commands:`)}`; + Array.from(client.executables.values()).sort((a, b) => a.name > b.name ? 1 : -1).forEach(e => s += `\n\n${sp}<${chalk.hex('#b57124')(e.name)}> - ${chalk.greenBright(e.usage)}\n${sp}${e.description} > ${chalk.gray(e.args.length ? `-${e.args.join(', -')}` : 'No args')}`); + return console.log(s.slice(0, s.length - 2)); + } + } +}; \ No newline at end of file diff --git a/executables/reload.js b/executables/reload.js new file mode 100644 index 0000000..0f08e7a --- /dev/null +++ b/executables/reload.js @@ -0,0 +1,68 @@ +const chalk = require('chalk'); +const fs = require('fs'); +const ora = require('ora'); +const Discord = require('discord.js'); + +module.exports = { + name: "reload", + description: "Reloads the client without restarting it.", + help: "Reloads client. Use -cmd, -event, -resp, or -exec flags to fine-tune the results.", + usage: "help [command]", + args: ['cmd', 'event', 'resp', 'exec'], + execute(client, text, args, cmd) { + let timer = new Date().getTime(); + let commands = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); + let dirSet = new Map(); + fs.readdirSync('./commands').filter(file => !file.includes('.')).forEach(dir => fs.readdirSync(`./commands/${dir}`).filter(file => file.endsWith('.js')).forEach(x => {commands.push(x); dirSet.set(x, dir)})); + console.log(`${chalk.gray('[CONS]')} >> [${chalk.blue(`RELOAD`)}] -> Clean (no-argument) reload:`); + console.log(`${chalk.yellow('[WARN]')} >> ${chalk.gray('Reload:')} ${chalk.white('All commands and events are being reloaded!')}\n`); + + let cmdspinner = ora(chalk.blue('Loading Commands')).start(); + ['commands', 'aliases'].forEach(x => client[x] = new Discord.Collection()); + for (let commandf of commands) { + if (Object.keys(require.cache).includes(require.resolve(`../commands/${dirSet.has(commandf) ? `${dirSet.get(commandf)}/`: ''}${commandf}`))) {delete require.cache[require.resolve(`../commands/${dirSet.has(commandf) ? `${dirSet.get(commandf)}/`: ''}${commandf}`)];} + let command = require(`../commands/${dirSet.has(commandf) ? `${dirSet.get(commandf)}/`: ''}${commandf}`); + client.commands.set(command.name, command); + if (command.aliases) {command.aliases.forEach(a => client.aliases.set(a, command.name));} + } + cmdspinner.stop(); cmdspinner.clear(); + console.log(`${chalk.gray('[PROC]')} >> ${chalk.blue('Loaded all Commands')}`); + + let eventspinner = ora(chalk.blue('Loading Events')).start(); + let eventFilter = fs.readdirSync('./events/').filter(x => x.endsWith('.js')); + for (let file of eventFilter) { + let evtName = file.split('.')[0]; + if (Object.keys(require.cache).includes(require.resolve('../events/' + file))) {delete require.cache[require.resolve('../events/' + file)];} + let evt = require('../events/' + file); + client.removeAllListeners(evtName); + client.on(evtName, evt.bind(null, client)); + } + eventspinner.stop(); eventspinner.clear(); + console.log(`${chalk.gray('[PROC]')} >> ${chalk.blue('Loaded all Events')}`); + + let rspspinner = ora(chalk.blue('Loading Responses')).start(); + let responses = fs.readdirSync('./responses').filter(file => file.endsWith('.js')); + client.responses.triggers = []; + for (let responsef of responses) { + if (Object.keys(require.cache).includes(require.resolve(`../responses/${responsef}`))) {delete require.cache[require.resolve(`../responses/${responsef}`)];} + let response = require(`../responses/${responsef}`); + client.responses.triggers.push([response.name, response.condition]); + client.responses.commands.set(response.name, response); + } + rspspinner.stop(); rspspinner.clear(); + console.log(`${chalk.gray('[PROC]')} >> ${chalk.blue('Loaded all Responses')}`); + + let exespinner = ora(chalk.blue('Loading Console Commands')).start(); + let executables = fs.readdirSync('./executables').filter(file => file.endsWith('.js')); + for (let execf of executables) { + if (Object.keys(require.cache).includes(require.resolve(`../executables/${execf}`))) {delete require.cache[require.resolve(`../executables/${execf}`)];} + var exec = require(`../executables/${execf}`); + client.executables.set(exec.name, exec); + } + exespinner.stop(); exespinner.clear(); + console.log(`${chalk.gray('[PROC]')} >> ${chalk.blue('Loaded all Console Commands')}`); + + console.log(`\n${chalk.gray('[INFO]')} >> Client refresh successful.`); + return console.log(`${chalk.gray('[CONS]')} >> ${chalk.greenBright(`Done!`)} Reloaded ${chalk.blue(commands.length)} ${chalk.blueBright(`commands`)}, ${chalk.blue(eventFilter.length)} ${chalk.blueBright(`events`)}, and ${chalk.blue(responses.length)} ${chalk.blueBright(`responses`)} in ${chalk.green(`${new Date().getTime() - timer}ms`)}.`); + } +}; \ No newline at end of file diff --git a/handle/command.js b/handle/command.js index a6800c8..2cdbced 100644 --- a/handle/command.js +++ b/handle/command.js @@ -10,17 +10,21 @@ module.exports = client => { //console.log(''); //let cora = ora(`${chalk.white("Loading commands into client.")} ${chalk.blue("[")}${chalk.blueBright("0")}${chalk.blue("/")}${chalk.blueBright(`${commands.length}`)}${chalk.blue("]")}`).start(); - let num = 0; + //let num = 0; commands.sort(); console.log(`\n${chalk.gray('[BOOT]')} >> ${chalk.blue('Getting Commands...')}\n`); for (let commandf of commands) { - num++; + //num++; //cora.text = `${chalk.white("Loading commands into client.")} ${chalk.blue("[")}${chalk.blueBright(`${num}`)}${chalk.blue("/")}${chalk.blueBright(`${commands.length}`)}${chalk.blue("]")}`; if (Object.keys(require.cache).includes(require.resolve(`../commands/${dirSet.has(commandf) ? `${dirSet.get(commandf)}/`: ''}${commandf}`))) {delete require.cache[require.resolve(`../commands/${dirSet.has(commandf) ? `${dirSet.get(commandf)}/`: ''}${commandf}`)];} let command = require(`../commands/${dirSet.has(commandf) ? `${dirSet.get(commandf)}/`: ''}${commandf}`); - client.commands.set(command.name, command); - if (command.aliases) {command.aliases.forEach(a => client.aliases.set(a, command.name));} - console.log(`${chalk.gray('[LOAD]')} >> ${chalk.blueBright('Loaded Command')} ${chalk.white(command.name)} ${chalk.blueBright('with')} ${chalk.white(command.aliases && command.aliases.length ? command.aliases.length : 0)} ${chalk.blueBright('aliases')}`); + const addCommand = (command) => { + client.commands.set(command.name, command); + if (command.aliases) {command.aliases.forEach(a => client.aliases.set(a, command.name));} + console.log(`${chalk.gray('[LOAD]')} >> ${chalk.blueBright('Loaded Command')} ${chalk.white(command.name)} ${chalk.blueBright('with')} ${chalk.white(command.aliases && command.aliases.length ? command.aliases.length : 0)} ${chalk.blueBright('aliases')}`); + }; + if (command.commands) {command.commands.forEach(cmd => addCommand(cmd));} + else {addCommand(command);} } //cora.stop(); cora.clear(); //console.log(`${chalk.gray('[BOOT]')} >> ${chalk.blue('Getting Commands...')}\n`); diff --git a/handle/console.js b/handle/console.js new file mode 100644 index 0000000..16587cc --- /dev/null +++ b/handle/console.js @@ -0,0 +1,14 @@ +const fs = require('fs'); +const chalk = require('chalk'); + +module.exports = client => { + var executables = fs.readdirSync('./executables').filter(file => file.endsWith('.js')); + console.log(`\n${chalk.gray('[BOOT]')} >> ${chalk.blue('Getting Console Commands...')}\n`); + for (let execf of executables) { + if (Object.keys(require.cache).includes(require.resolve(`../executables/${execf}`))) {delete require.cache[require.resolve(`../executables/${execf}`)];} + var exec = require(`../executables/${execf}`); + client.executables.set(exec.name, exec); + console.log(`${chalk.gray('[LOAD]')} >> ${chalk.blueBright('Loaded CMD')} ${chalk.white(exec.name)}`); + } + console.log(`\n${chalk.gray('[BOOT]')} >> ${chalk.blue('Loaded all Executables.')}`); +}; \ No newline at end of file diff --git a/package.json b/package.json index eb2a3d3..42f95e2 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,12 @@ "main": "bot.js", "author": "NatsukiDev", "dependencies": { + "@discordjs/rest": "^0.1.0-canary.0", "@discordjs/voice": "^0.6.0", "chalk": "^4.1.0", "cron": "^1.8.2", "dblapi.js": "^2.4.1", - "discord.io": "https://github.com/woor/discord.io/tarball/gateway_v6", + "discord-api-types": "^0.22.0", "discord.js": "^13.1.0", "lastfm": "^0.9.0", "manyitems": "^1.0.2", @@ -19,7 +20,6 @@ "node-fetch": "^2.6.1", "ora": "^5.3.0", "swwrap": "^1.0.0", - "winston": "^3.3.3", "ws": "^7.4.6" }, "engines": { diff --git a/util/pagination.js b/util/pagination.js index 32eb20a..17df12a 100644 --- a/util/pagination.js +++ b/util/pagination.js @@ -87,7 +87,7 @@ class Pagination { let filter = user && user.toLowerCase().trim() !== 'any' ? (r, u) => { return u.id === user.trim() && emoji.includes(r.emoji.name); } : (r) => { return emoji.includes(r.emoji.name); }; - this.controllers.collector = this.message.createReactionCollector({ filter, time: 450000 }); + this.controllers.collector = this.message.createReactionCollector({ filter: filter, time: 450000 }); this.controllers.collector.on('collect', async (r) => { let functions = { '⬅': () => { return this.prevPage(); },