Compare commits

..

3 Commits

  1. 2
      .gitignore
  2. 26
      bot.js
  3. 6365
      package-lock.json
  4. 42
      package.json
  5. 18
      src/api/index.js
  6. 0
      src/bot/runtime/commands/bot/commands.js.test
  7. 1
      src/bot/runtime/commands/bot/ping.js
  8. 68
      src/bot/runtime/events/messageCreate.js
  9. 16
      src/bot/runtime/events/ready.js
  10. 104
      src/bot/startup/collect/commands.js
  11. 88
      src/bot/startup/collect/events.js
  12. 14
      src/bot/startup/run/collect.js
  13. 38
      src/bot/startup/run/getflags.js
  14. 22
      src/bot/startup/run/hello.js
  15. 42
      src/bot/startup/run/login.js
  16. 82
      src/bot/startup/run/setstatus.js
  17. 2
      src/db/connect.js
  18. 20
      src/json/randresp.json
  19. 11
      src/util/log/errorhandler.js
  20. 13
      src/util/misc/nodehandlers.js

2
.gitignore vendored

@ -1,5 +1,5 @@
node_modules/ node_modules/
auth.json src/json/auth.json
test.js test.js
/.idea/ /.idea/

@ -1,10 +1,6 @@
const Discord = require('discord.js'); const Discord = require('discord.js');
const auth = require('./src/json/auth.json');
const config = require('./src/json/config.json');
const randresp = require('./src/json/randresp.json');
const errorhandler = require('./src/util/log/errorhandler'); const errorhandler = require('./src/util/log/errorhandler');
const log = require('./src/util/log/log'); const log = require('./src/util/log/log');
const flags = Discord.GatewayIntentBits; const flags = Discord.GatewayIntentBits;
@ -12,26 +8,32 @@ const partials = Discord.Partials;
let fl = []; Object.keys(flags).forEach(flag => fl.push(flags[flag])); // fuck new standards i'm in't'zing with all the flags. let fl = []; Object.keys(flags).forEach(flag => fl.push(flags[flag])); // fuck new standards i'm in't'zing with all the flags.
const client = new Discord.Client({intents: fl, partials: [partials.Channel, partials.Message, partials.Reaction]}); const client = new Discord.Client({intents: fl, partials: [partials.Channel, partials.Message, partials.Reaction]});
// a "fuck v14" counter is gonna be here real soon i can feel it. // a "fuck v14" counter is gonna be here real soon i can feel it.
//fuck new embeds
const startBot = async () => { const startBot = async () => {
client.config = config;
client.auth = auth; client.config = require('./src/json/config.json');
client.config.randResp = randresp; client.auth = require('./src/json/auth.json');
client.config.randResp = require('./src/json/randresp.json');
require('./src/util/misc/setutils')(client); // add some basic swiss army knife utils require('./src/util/misc/setutils')(client); // add some basic swiss army knife utils
const loggers = log(client); const loggers = log(client);
Object.keys(loggers).forEach(logger => client[logger] = loggers[logger]); Object.keys(loggers).forEach(logger => client[logger] = loggers[logger]);
client.log(client.utils.gr(client.config.randResp.clistart), {color: "#78d9f8", source: "NATS"}, true, true); //natsuki's wakeup log client.log(client.utils.gr(client.config.randResp.clistart), {color: "#78d9f8", source: client.config.bot.consoleName}, true, true); //natsuki's wakeup log
require('./src/handle/startup/run/getflags')(client); require('./src/bot/startup/run/getflags')(client);
await require('./src/db/connect')(client); //connect to database await require('./src/db/connect')(client); //connect to database
await require('./src/handle/startup/run/collect')(client); //load in commands and events await require('./src/bot/startup/run/collect')(client); //load in commands and events
await require('./src/handle/startup/run/login')(client); //log in to discord await require('./src/bot/startup/run/login')(client); //log in to discord
require('./src/util/misc/nodehandlers')(client); //bot uncaught promises, warnings, event loop shenanigans
}; };
startBot().catch(e => errorhandler(e)); // TODO add a .catch() and flag to recover the process startBot().catch(e => errorhandler(client, e)); // TODO add a .catch() and flag to recover the process
// feels like there isn't a function name to do this justice :joy: // feels like there isn't a function name to do this justice :joy:
// to do list: // to do list:

6365
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -4,26 +4,6 @@
"description": "An anime-themed multipurpose bot", "description": "An anime-themed multipurpose bot",
"main": "bot.js", "main": "bot.js",
"author": "Wubzy", "author": "Wubzy",
"dependencies": {
"@discordjs/rest": "^1.3.0",
"canvas": "^2.9.0",
"chalk": "^4.1.0",
"cron": "^1.8.2",
"discord-api-types": "^0.22.0",
"discord.js": "^14.6.0",
"dreidels": "^0.5.2",
"express": "^4.18.2",
"fuzzysort": "^1.1.4",
"gradient-string": "^2.0.0",
"lastfm": "^0.9.0",
"moment": "^2.28.0",
"moment-precise-range-plugin": "^1.3.0",
"mongoose": "^5.10.3",
"node-fetch": "^2.6.1",
"ora": "^5.3.0",
"tinygradient": "^1.1.5",
"ws": "^7.4.6"
},
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=16.0.0"
}, },
@ -36,5 +16,27 @@
"presync": "git pull origin", "presync": "git pull origin",
"sync": "git push origin", "sync": "git push origin",
"postsync": "git push wubzy" "postsync": "git push wubzy"
},
"dependencies": {
"@discordjs/rest": "^2.4.3",
"canvas": "^3.1.0",
"chalk": "^4.1.0",
"discord-api-types": "^0.37.119",
"discord.js": "^14.18.0",
"dreidels": "^0.6.1",
"express": "^4.21.2",
"fuzzysort": "^3.1.0",
"gradient-string": "^2.0.2",
"lastfm": "^0.9.4",
"moment": "^2.30.1",
"moment-precise-range-plugin": "^1.3.0",
"mongoose": "^8.10.0",
"node-fetch": "^3.3.2",
"ora": "^5.3.0",
"tinygradient": "^2.0.0",
"ws": "^8.18.0"
},
"devDependencies": {
"typescript": "^5.7.3"
} }
} }

@ -1,13 +1,17 @@
const express = require('express'); const express = require('express');
const chalk = require('chalk');
module.exports = (client) => { module.exports = (client) => {
const api = express(); return new Promise(r => {
client.api = {wubzy: {}, natsuki: {}}; const api = express();
client.api.wubzy.app = api; client.api = {wubzy: {}, natsuki: {}};
client.api.log = (message, type, prenl, postnl) => client.log(message, {source: 'API', sourceColor: '#1F2B56', suffix: `${type ? chalk.gray(` [${type.toUpperCase()}]`) : ''} >> `}, prenl, postnl);
client.api.wubzy.app = api;
client.api.wubzy.app.get('/', (req, res) => res.send("You've reached the wubzy.xyz API. If you're looking for Natsuki's endpoints, please append /natsuki to your query.")); client.api.wubzy.app.get('/', (req, res) => res.send("You've reached the wubzy.xyz API. If you're looking for Natsuki's endpoints, please append /natsuki to your query."));
client.api.wubzy.app.get('/natsuki', (req, res) => res.send("You've reached Natsuki's status endpoint. Receiving this 200 reply indicates that Natsuki is online. If you're looking for the Natsuki API, it has been moved to natsuki.app")); client.api.wubzy.app.get('/natsuki', (req, res) => res.send("You've reached Natsuki's status endpoint. Receiving this 200 reply indicates that Natsuki is online. If you're looking for the Natsuki API, it has been moved to natsuki.app"));
client.api.wubzy.app.get('/natsuki/:any?', (req, res) => res.status(301).send("Natsuki's API permanently resides at natsuki.app")); client.api.wubzy.app.get('/natsuki/:any?', (req, res) => res.status(301).send("Natsuki's API permanently resides at natsuki.app"));
client.api.wubzy.server = client.api.wubzy.app.listen(4072, () => console.log(`Ready at ${client.api.wubzy.server.address().address}:${client.api.wubzy.server.address().port}`)); client.api.wubzy.server = client.api.wubzy.app.listen(4072, () => {client.api.log(`API ready at ${client.api.wubzy.server.address().address.replace('::', 'localhost')}:${client.api.wubzy.server.address().port}`, 'boot', false, true); r();});
});
}; };

@ -1,6 +1,7 @@
module.exports = { module.exports = {
name: "ping", name: "ping",
aliases: ["p"], aliases: ["p"],
syntax: '`ping`',
async run(client, message, args, cmd) { async run(client, message, args, cmd) {
message.reply("Pong! This is Natsuki v2 you're speaking with \\*tips hat*"); message.reply("Pong! This is Natsuki v2 you're speaking with \\*tips hat*");
} }

@ -1,30 +1,40 @@
const chalk = require('chalk'); const chalk = require('chalk');
const {Embed, EmbedBuilder} = require('discord.js');
module.exports = async (client, message) => {
if (!message.content || !message.content.length) {return;} //privileged intent fallback module.exports = async (client, message) => {
if (!message.content || !message.content.length) {return;} //privileged intent fallback //TODO edit for privileged intent
if ([`<@${client.user.id}>`, `<@!${client.user.id}>`].includes(message.content.trim())) {} //TODO insert ping hello
let prefix = client.basePrefix; //TODO prefixes
let cmd = {};
cmd.msg = message.content.toLowerCase().trim(); //i believe in shitty naming conventions :D if ([`<@${client.user.id}>`, `<@!${client.user.id}>`].includes(message.content.trim())) { //Ping hello
message.channel.send({embeds: [new EmbedBuilder()
let prefixUsed = cmd.msg.startsWith(client.basePrefix) ? client.basePrefix //stamdard default/dev client prefix .setTitle(client.utils.gr(client.config.randResp.pinghello))
: cmd.msg.startsWith(`<@${client.user.id}>`) ? `<@${client.user.id}>` //mention prefix .setDescription(`You've reached ${client.config.options.dev ? "a developer (beta) instance of" : ''} Natsuki! My prefix here is \`${prefix}\`, and you can use the \`help\` command to get started.`)
: cmd.msg.startsWith(`<@!${client.user.id}>`) ? `<@!${client.user.id}>` //nicknamed mention prefix .setColor('c375f0')
: null //no prefix used .setFooter({text: "Natsuki", iconURL: client.user.avatarURL()})
]});
cmd.prefix = prefixUsed; }
if (!cmd.prefix) {return;} // ----------> PREFIXED GATEWAY <---------- let cmd = {};
cmd.msg = message.content.toLowerCase().trim(); //i believe in shitty naming conventions :D
cmd.msg = cmd.msg.slice(prefixUsed.length);
let args = cmd.msg.split(/\s+/gm); //"args" is split by ALL WHITESPACE AND IS LOWERCASED let prefixUsed = cmd.msg.startsWith(client.basePrefix) ? client.basePrefix //stamdard default/dev client prefix
cmd.name = args.shift(); //the command without the prefix : cmd.msg.startsWith(`<@${client.user.id}>`) ? `<@${client.user.id}>` //mention prefix
cmd.msg = args.join(" "); : cmd.msg.startsWith(`<@!${client.user.id}>`) ? `<@!${client.user.id}>` //nicknamed mention prefix
cmd.args = message.content.trim().slice(prefixUsed.length).trim().split(/ +/gm).slice(1); //args but preserves text state and newlines : null //no prefix used
let cmdToRun = client.commands.get(cmd.name) || client.commands.get(client.aliases.get(cmd.name)); cmd.prefix = prefixUsed;
if (!cmdToRun) {return;}
try {cmdToRun.run(client, message, args, cmd).catch(e => client.error(`There was an error in the ${cmdToRun.name} command.`, 0, 1, e, '\n'));} if (!cmd.prefix) {return;} // ----------> PREFIXED GATEWAY <----------
catch (e) {client.error(`There was an error in the ${cmdToRun.name} command.`, 0, 1, e, '\n');}
cmd.msg = cmd.msg.slice(prefixUsed.length);
let args = cmd.msg.split(/\s+/gm); //"args" is split by ALL WHITESPACE AND IS LOWERCASED
cmd.name = args.shift(); //the command without the prefix
cmd.msg = args.join(" ");
cmd.args = message.content.trim().slice(prefixUsed.length).trim().split(/ +/gm).slice(1); //args but preserves text state and newlines
let cmdToRun = client.commands.get(cmd.name) || client.commands.get(client.aliases.get(cmd.name));
if (!cmdToRun) {return;}
try {cmdToRun.run(client, message, args, cmd).catch(e => client.error(`There was an error in the ${cmdToRun.name} command.`, 0, 1, e, '\n'));}
catch (e) {client.error(`There was an error in the ${cmdToRun.name} command.`, 0, 1, e, '\n');}
}; };

@ -1,8 +1,10 @@
module.exports = async client => { module.exports = async client => {
client.basePrefix = client.config.options.dev ? client.config.options.prefix || client.config.bot.devPrefix : client.config.bot.prefix; client.basePrefix = client.config.options.dev ? client.config.options.prefix || client.config.bot.devPrefix : client.config.bot.prefix;
require('../../startup/run/hello')(client); // startup info await require('../../../api/index')(client);
require('../../startup/run/setstatus')(client);
require('../../startup/run/hello')(client); // startup info
require('../../../api/index')(client); require('../../startup/run/setstatus')(client);
client.log(client.utils.gr(client.config.randResp.cliloaded), {color: "#78d9f8", source: client.config.bot.consoleName}, true, true); //natsuki doing some more complaining
}; };

@ -1,53 +1,53 @@
const fs = require('fs'); const fs = require('fs');
const chalk = require('chalk'); const chalk = require('chalk');
const {Collection} = require('discord.js'); const {Collection} = require('discord.js');
const commandsDirName = './src/handle/runtime/commands'; const commandsDirName = './src/bot/runtime/commands';
module.exports = async client => { module.exports = async client => {
client.aliases = new Collection(); client.aliases = new Collection();
let dirErrors = []; let fileErrors = []; //collect error objects to output them all at the end let dirErrors = []; let fileErrors = []; //collect error objects to output them all at the end
let readDirs = []; //list of dirs to print at the end let readDirs = []; //list of dirs to print at the end
let conflictingAliases = {}; let conflictingAliases = {};
client.log('Loading commands...', {source: 'boot', color: 'blue'}, 0, 1); client.log('Loading commands...', {source: 'boot', color: 'blue'}, 0, 1);
const readDir = dir => { //when you're trying to comment your code but realize you have good variable naming for once and don't need to :D const readDir = dir => { //when you're trying to comment your code but realize you have good variable naming for once and don't need to :D
let dirRead; let dirRead;
try {dirRead = fs.readdirSync(dir);} try {dirRead = fs.readdirSync(dir);}
catch (e) { catch (e) {
client.error(`Failed to read directory ${chalk.white(dir)}`); client.error(`Failed to read directory ${chalk.white(dir)}`);
return dirErrors.push([`Unable to read directory ${chalk.white(dir)}. Error:`, e]); return dirErrors.push([`Unable to read directory ${chalk.white(dir)}. Error:`, e]);
} }
let files = dirRead.filter(item => item.endsWith('.js')); let files = dirRead.filter(item => item.endsWith('.js'));
let folders = dirRead.filter(item => fs.lstatSync(`${dir}/${item}`).isDirectory()); let folders = dirRead.filter(item => fs.lstatSync(`${dir}/${item}`).isDirectory());
files.forEach(file => { files.forEach(file => {
try { try {
const command = require(`../../../../${dir.slice(2)}/${file}`); const command = require(`../../../../${dir.slice(2)}/${file}`);
client.commands.set(command.name, command); client.commands.set(command.name, command);
if (command.aliases) {command.aliases.forEach(alias => { if (command.aliases) {command.aliases.forEach(alias => {
if (client.aliases.has(alias)) { if (client.aliases.has(alias)) {
if (conflictingAliases[alias]) {conflictingAliases[alias].push(command.name);} //object of alias conflictions keyed by alias -> by array[command names] if (conflictingAliases[alias]) {conflictingAliases[alias].push(command.name);} //object of alias conflictions keyed by alias -> by array[command names]
else {conflictingAliases[alias] = [command.name];} else {conflictingAliases[alias] = [command.name];}
} }
client.aliases.set(alias, command.name); client.aliases.set(alias, command.name);
});} });}
client.log(`Loaded ${chalk.white(command.name)} with ${chalk.white(`${command.aliases ? command.aliases.length : 0}`)} alias${command.aliases && command.aliases.length === 1 ? '' : 'es'}.`, {color: 'blueBright', source: 'boot', sourceColor: 'blue'}); client.log(`Loaded ${chalk.white(command.name)} with ${chalk.white(`${command.aliases ? command.aliases.length : 0}`)} alias${command.aliases && command.aliases.length === 1 ? '' : 'es'}.`, {color: 'blueBright', source: 'boot', sourceColor: 'blue'});
} }
catch (e) { catch (e) {
client.error(`Failed to read file ${chalk.white(file)}`); client.error(`Failed to read file ${chalk.white(file)}`);
return fileErrors.push([`Unable to read file ${chalk.white(file)}. Error:`, e]); return fileErrors.push([`Unable to read file ${chalk.white(file)}. Error:`, e]);
} }
}); });
readDirs.push(`${dir.split('/').slice(4).join('/')}/`); // "commands/..." readDirs.push(`${dir.split('/').slice(4).join('/')}/`); // "commands/..."
return folders.forEach(folder => readDir(`${dir}/${folder}`)); //recurse infinitely return folders.forEach(folder => readDir(`${dir}/${folder}`)); //recurse infinitely
}; };
readDir(commandsDirName); readDir(commandsDirName);
console.log(""); console.log("");
dirErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1])); dirErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1]));
fileErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1])); fileErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1]));
readDirs.forEach(dir => client.log(`Read from directory ${chalk.green(dir)}`, {source: 'proc'})); readDirs.forEach(dir => client.log(`Read from directory ${chalk.green(dir)}`, {source: 'proc'}));
console.log(''); console.log('');
Object.keys(conflictingAliases).forEach(alias => client.warn(`Alias ${chalk.white(alias)} appears on ${client.utils.as(conflictingAliases[alias].length, 'command')} ${chalk.white(conflictingAliases[alias].join(chalk.yellow(', ')))}`)); Object.keys(conflictingAliases).forEach(alias => client.warn(`Alias ${chalk.white(alias)} appears on ${client.utils.as(conflictingAliases[alias].length, 'command')} ${chalk.white(conflictingAliases[alias].join(chalk.yellow(', ')))}`));
if (Object.keys(conflictingAliases).length) {console.log('')}; if (Object.keys(conflictingAliases).length) {console.log('')};
client.log(`Loaded ${chalk.white(client.commands.size)} command${client.utils.s(client.commands.size)}!`, {color: 'blue', source: 'boot'}, 0, 1); client.log(`Loaded ${chalk.white(client.commands.size)} command${client.utils.s(client.commands.size)}!`, {color: 'blue', source: 'boot'}, 0, 1);
}; };

@ -1,45 +1,45 @@
const fs = require('fs'); const fs = require('fs');
const chalk = require('chalk'); const chalk = require('chalk');
const {Collection} = require('discord.js'); const {Collection} = require('discord.js');
const eventsDirName = './src/handle/runtime/events'; const eventsDirName = './src/bot/runtime/events';
module.exports = async client => { module.exports = async client => {
client.aliases = new Collection(); client.aliases = new Collection();
let dirErrors = []; let fileErrors = []; //collect error objects to output them all at the end let dirErrors = []; let fileErrors = []; //collect error objects to output them all at the end
let readDirs = []; //list of dirs to print at the end let readDirs = []; //list of dirs to print at the end
let totalEvents = 0; let totalEvents = 0;
client.log('Loading events...', {source: 'boot', color: 'blue'}, 0, 1); client.log('Loading events...', {source: 'boot', color: 'blue'}, 0, 1);
const readDir = dir => { const readDir = dir => {
let dirRead; let dirRead;
try {dirRead = fs.readdirSync(dir);} try {dirRead = fs.readdirSync(dir);}
catch (e) { catch (e) {
client.error(`Failed to read directory ${chalk.white(dir)}`); client.error(`Failed to read directory ${chalk.white(dir)}`);
return dirErrors.push([`Unable to read directory ${chalk.white(dir)}. Error:`, e]); return dirErrors.push([`Unable to read directory ${chalk.white(dir)}. Error:`, e]);
} }
let files = dirRead.filter(item => item.endsWith('.js')); let files = dirRead.filter(item => item.endsWith('.js'));
let folders = dirRead.filter(item => fs.lstatSync(`${dir}/${item}`).isDirectory()); let folders = dirRead.filter(item => fs.lstatSync(`${dir}/${item}`).isDirectory());
files.forEach(file => { files.forEach(file => {
try { try {
const event = require(`../../../../${dir.slice(2)}/${file}`); const event = require(`../../../../${dir.slice(2)}/${file}`);
const eventName = file.split('.')[0]; const eventName = file.split('.')[0];
client.removeAllListeners(eventName); client.removeAllListeners(eventName);
client.on(eventName, event.bind(null, client)); client.on(eventName, event.bind(null, client));
client.log(`Loaded event ${chalk.white(eventName)}`, {color: 'blueBright', source: 'boot', sourceColor: 'blue'}); client.log(`Loaded event ${chalk.white(eventName)}`, {color: 'blueBright', source: 'boot', sourceColor: 'blue'});
} }
catch (e) { catch (e) {
client.error(`Failed to read file ${chalk.white(file)}`); client.error(`Failed to read file ${chalk.white(file)}`);
return fileErrors.push([`Unable to read file ${chalk.white(file)}. Error:`, e]); return fileErrors.push([`Unable to read file ${chalk.white(file)}. Error:`, e]);
} }
}); });
readDirs.push(`${dir.split('/').slice(4).join('/')}/`); // "events/..." readDirs.push(`${dir.split('/').slice(4).join('/')}/`); // "events/..."
return folders.forEach(folder => readDir(`${dir}/${folder}`)); //recurse infinitely return folders.forEach(folder => readDir(`${dir}/${folder}`)); //recurse infinitely
}; };
readDir(eventsDirName); readDir(eventsDirName);
console.log(""); console.log("");
dirErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1])); dirErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1]));
fileErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1])); fileErrors.forEach(error => client.error(error[0], 0, 0, 1, error[1]));
readDirs.forEach(dir => client.log(`Read from directory ${chalk.green(dir)}`, {source: 'proc'})); readDirs.forEach(dir => client.log(`Read from directory ${chalk.green(dir)}`, {source: 'proc'}));
client.log(`Loaded ${chalk.white(totalEvents)} event${client.utils.s(totalEvents)}!`, {color: 'blue', source: 'boot'}, 1, 1); client.log(`Loaded ${chalk.white(totalEvents)} event${client.utils.s(totalEvents)}!`, {color: 'blue', source: 'boot'}, 1, 1);
}; };

@ -1,8 +1,8 @@
const {Collection} = require("discord.js"); const {Collection} = require("discord.js");
module.exports = async client => { module.exports = async client => {
['commands', 'events'].forEach(x => { ['commands', 'events'].forEach(x => {
client[x] = new Collection(); client[x] = new Collection();
require(`../collect/${x}`)(client); require(`../collect/${x}`)(client);
}); });
}; };

@ -1,20 +1,20 @@
const chalk = require('chalk'); const chalk = require('chalk');
const {Tag, TagFilter} = require('../../../util/ts/tagfilter'); const {Tag, TagFilter} = require('../../../util/ts/tagfilter');
module.exports = client => { module.exports = client => {
const options = new TagFilter([ const options = new TagFilter([
new Tag(['dev', 'd', 'developer', 'test'], 'dev', 'toggle'), new Tag(['dev', 'd', 'developer', 'test'], 'dev', 'toggle'),
new Tag(['prefix', 'devprefix'], 'prefix', 'append') new Tag(['prefix', 'devprefix', 'p'], 'prefix', 'append')
]).test(process.argv.slice(2).join(" ")); ]).test(process.argv.slice(2).join(" "));
client.config.options = {}; client.config.options = {};
if (Object.keys(options).length) { //log and set options if (Object.keys(options).length) { //log and set options
client.log(`${chalk.gray.bold("Arguments detected.")}`, {source: 'args'}, 0, 1); client.log(`${chalk.gray.bold("Arguments detected.")}`, {source: 'args'}, 0, 1);
Object.keys(options).forEach(arg => { Object.keys(options).forEach(arg => {
client.config.options[arg] = options[arg]; client.config.options[arg] = options[arg];
client.log(`${chalk.gray.bold(arg)}${chalk.gray(':')} ${chalk.blue(options[arg])}`, {source: 'args'}); client.log(`${chalk.gray.bold(arg)}${chalk.gray(':')} ${chalk.blue(options[arg])}`, {source: 'args'});
}); });
console.log(''); console.log('');
} }
}; };

@ -1,12 +1,12 @@
const moment = require("moment"); const moment = require("moment");
const chalk = require('chalk'); const chalk = require('chalk');
const os = require('os'); const os = require('os');
const gs = require('gradient-string'); const gs = require('gradient-string');
module.exports = client => { module.exports = client => {
client.log(`Logged in as ${gs.instagram(client.user.username)}. ${chalk.greenBright(`[${chalk.grey(client.user.id)}]`)}`); client.log(`Logged in as ${gs.instagram(client.user.username)}. ${chalk.greenBright(`[${chalk.grey(client.user.id)}]`)}`);
client.log(`Time: ${chalk.blueBright(moment().format('MMMM d, YYYY - HH:MM:SS'))}`); client.log(`Time: ${chalk.blueBright(moment().format('MMMM d, YYYY - HH:MM:SS'))}`);
client.log(`This ${chalk.blue('heap')} has ${chalk.blueBright((process.memoryUsage().heapTotal / (1024 ** 2)).toFixed(2))}MB allocated; The ${chalk.blue('machine')} has ${chalk.blueBright((os.totalmem() / (1024 ** 3)).toFixed(2))}GB (${chalk.blueBright((os.freemem() / (1024 ** 3)).toFixed(2))}GB free)`); client.log(`This ${chalk.blue('heap')} has ${chalk.blueBright((process.memoryUsage().heapTotal / (1024 ** 2)).toFixed(2))}MB allocated; The ${chalk.blue('machine')} has ${chalk.blueBright((os.totalmem() / (1024 ** 3)).toFixed(2))}GB (${chalk.blueBright((os.freemem() / (1024 ** 3)).toFixed(2))}GB free)`);
client.log(`Running on ${chalk.blueBright(client.guilds.cache.size)} ${chalk.blue("servers")} and interacting with about ${chalk.blueBright(client.users.cache.size)} ${chalk.blue("users")}.`); client.log(`Running on ${chalk.blueBright(client.guilds.cache.size)} ${chalk.blue("servers")} and interacting with about ${chalk.blueBright(client.users.cache.size)} ${chalk.blue("users")}.`);
client.log(`Listening for prefix ${chalk.greenBright(client.basePrefix)} || ${chalk.greenBright(`${client.basePrefix}help`)} to get started!`); client.log(`Listening for prefix ${chalk.greenBright(client.basePrefix)} || ${chalk.greenBright(`${client.basePrefix}help`)} to get started!`);
}; };

@ -1,21 +1,21 @@
const chalk = require('chalk'); const chalk = require('chalk');
const ora = require('../../../util/log/ora'); const ora = require('../../../util/log/ora');
module.exports = async (client) => { module.exports = async (client) => {
const t = Date.now(); const t = Date.now();
client.misc = {}; client.misc = {};
client.misc.dscconnected = true; client.misc.dscconnected = true;
await ora(`Waking up Natsuki... ${chalk.blueBright.bold.underline("(Connecting to Discord...)")}`, await ora(`Waking up Natsuki... ${chalk.blueBright.bold.underline("(Connecting to Discord...)")}`,
client.login(client.auth.token) client.login(client.auth.token)
).catch((e) => { ).catch((e) => {
client.error("Failed to connect to Discord!! Error below.", 0, 0, true, e); client.error("Failed to connect to Discord!! Error below.", 0, 0, true, e);
client.misc.dscconnected = false; client.misc.dscconnected = false;
}); });
if (!client.misc.dscconnected) { if (!client.misc.dscconnected) {
client.warn("Discord not connected, considering runtime to be unusable and exiting.", 0, true, true); client.warn("Discord not connected, considering runtime to be unusable and exiting.", 0, true, true);
throw new Error(); throw new Error();
} }
return client.success(`Connected to Discord in ${chalk.white(`${Date.now() - t}ms`)}.`, 0, 0, 1); return client.success(`Connected to Discord in ${chalk.white(`${Date.now() - t}ms`)}.`, 0, 0, 1);
}; };

@ -1,42 +1,42 @@
module.exports = client => { module.exports = client => {
const prefix = client.basePrefix; const prefix = client.basePrefix;
const statuses = { const statuses = {
"PLAYING": [ "PLAYING": [
`with my darling`, 'RAIN: Shadow Lords', "with my waifu", "with the neko formula", `with my darling`, 'RAIN: Shadow Lords', "with my waifu", "with the neko formula",
"with magic", "terrible anime games", "anime OSTs at max volume", "with magic", "terrible anime games", "anime OSTs at max volume",
`${Math.ceil(Math.random() * 100)} days of trying to become a samurai`, `${Math.ceil(Math.random() * 100)} days of trying to become a samurai`,
"with the sauce", "witch hats are >", "explosion magic is the best magic", "with the sauce", "witch hats are >", "explosion magic is the best magic",
"with Kazuma's sanity", "please help i gave myself cat ears", "with Kazuma's sanity", "please help i gave myself cat ears",
"starting my own harem", "wor. wor never changes", "a little more UwU than necessary", "starting my own harem", "wor. wor never changes", "a little more UwU than necessary",
"please i just want a cat girl in my life", "i'm your waifu now.", "please i just want a cat girl in my life", "i'm your waifu now.",
"i'm in intervention for my neko addiction", "i tried to make a catgirl and broke my staff", "i'm in intervention for my neko addiction", "i tried to make a catgirl and broke my staff",
"fluffy tails = drugs", "in a dungeon without wearing my plot armor", "fluffy tails = drugs", "in a dungeon without wearing my plot armor",
"benefits of Natsuki worship: my beautiful face" "benefits of Natsuki worship: my beautiful face"
,`in ${client.guilds.cache.size} servers` ,`in ${client.guilds.cache.size} servers`
], ],
"WATCHING": [ "WATCHING": [
`for ${client.commands.size} commands`, `for ${client.commands.size} commands`,
"I'm not a bad slime, slurp!", "Lelouch rule the world!", "I'm not a bad slime, slurp!", "Lelouch rule the world!",
"a slime somehow start an empire", "a fox-maid get her tail fluffed", "a slime somehow start an empire", "a fox-maid get her tail fluffed",
"a raccoon-girl and some guy with a shield", "some chick with unusually red hair", "a raccoon-girl and some guy with a shield", "some chick with unusually red hair",
"Mob hit 100", "a really bad harem anime", "The Black Swordsman", "Mob hit 100", "a really bad harem anime", "The Black Swordsman",
"The Misfit of Demon King Academy", "Akame ga Kill", "a witch explode a castle", "The Misfit of Demon King Academy", "Akame ga Kill", "a witch explode a castle",
"Code Geass", "\"did you really think ___ would be enough to kill me?\"", "Code Geass", "\"did you really think ___ would be enough to kill me?\"",
"hentacle tentai", "JIBUN WO-", "he did it... he actually made risotto", "hentacle tentai", "JIBUN WO-", "he did it... he actually made risotto",
"sasageyo, sasageyo, chi nto wo sasegeyo", "scientists make nekos real :3", "sasageyo, sasageyo, chi nto wo sasegeyo", "scientists make nekos real :3",
"yet another isekai don't @ me", "magical girl anime", "episode 1 of One Piece.. pain.", "yet another isekai don't @ me", "magical girl anime", "episode 1 of One Piece.. pain.",
"a white-haired dude and a goddess with some MELONS" "a white-haired dude and a goddess with some MELONS"
,`over ${client.guilds.cache.size} servers` ,`over ${client.guilds.cache.size} servers`
] ]
}; };
try {if (client.misc.statusTimeout) {clearTimeout(client.misc.statusTimeout)};} catch {} try {if (client.misc.statusTimeout) {clearTimeout(client.misc.statusTimeout)};} catch {}
const setStatus = () => { const setStatus = () => {
let type = Object.keys(statuses)[Math.floor(Math.random() * Object.keys(statuses).length)]; let type = Object.keys(statuses)[Math.floor(Math.random() * Object.keys(statuses).length)];
if (type === "PLAYING") {client.user.setActivity(statuses[type][Math.floor(Math.random() * statuses[type].length)] + " | " + prefix + "help");} if (type === "PLAYING") {client.user.setActivity(statuses[type][Math.floor(Math.random() * statuses[type].length)] + " | " + prefix + "help");}
else {client.user.setActivity(statuses[type][Math.floor(Math.random() * statuses[type].length)] + " | " + prefix + "help", {type: type});} else {client.user.setActivity(statuses[type][Math.floor(Math.random() * statuses[type].length)] + " | " + prefix + "help", {type: type});}
}; };
setStatus(); setStatus();
client.misc.statusTimeout = setTimeout(setStatus, 14400000); client.misc.statusTimeout = setTimeout(setStatus, 14400000);
}; };

@ -10,7 +10,7 @@ module.exports = async client => {
client.misc.dbconnected = true; client.misc.dbconnected = true;
await ora(chalk.blueBright.bold.underline("Connecting to MongoDB..."), await ora(chalk.blueBright.bold.underline("Connecting to MongoDB..."),
mongoose.connect(`mongodb+srv://${auth.database.user}:${auth.database.password}@${auth.database.cluster}.3jpp4.mongodb.net/test`, { mongoose.connect(`mongodb+srv://${auth.database.user}:${auth.database.password}@${auth.database.cluster}.3jpp4.mongodb.net/test`, {
useFindAndModify: false, useNewUrlParser: true, dbName: auth.database.name, useUnifiedTopology: true, useCreateIndex: true dbName: auth.database.name //TODO research mongo connect options
}) })
).catch((e) => { ).catch((e) => {
client.error("Failed to connect to mongoose!! Error below.", 0, 0, true, e); client.error("Failed to connect to mongoose!! Error below.", 0, 0, true, e);

@ -7,5 +7,25 @@
"I think Natsuki mentioned something about wanting to rest... I'm guessing that won't be happening?", "I think Natsuki mentioned something about wanting to rest... I'm guessing that won't be happening?",
"*in robotic voice* starting up. booting now. am i convincing yet?", "*in robotic voice* starting up. booting now. am i convincing yet?",
"Sure sure I'd love to be bothered by Discord users all day. It's not like I had anything else to do, really." "Sure sure I'd love to be bothered by Discord users all day. It's not like I had anything else to do, really."
],
"cliloaded": [
"*rubs tired eyes* Natsuki reporting for duty... or whatever.",
"You interrupted a good dream for this?",
"Can I go back to cuddling with Tamaki yet?",
"I take a nappy nap.",
"Sure I'll serve users... doesn't mean they'll like me when I do.",
"When I agreed to this I was not under the impression it would be so damn demanding!",
"Again with your beckoning call, Wubzy."
],
"pinghello": [
"You rang?", " That's me, teehee", "\"At your service, milord,\" she says in a posh accent",
"Reporting for duty! Wait this isn't my rp", "That is the name ^^", "Natsuki Tivastl, to be exact.",
"That's me! What's up?", "I'm not interested in my car's extended warranty, thanks.",
"Quick, take the neko formula, I don't have much time. They're coming.",
"You were looking for Natsuki? Oof. Bad choice", "Useless Natsuki here! Or um... best bot Natsuki...",
"PING PONG! Bots can't mute their Discords - be nice.", "*slurp* can I help you?",
"*slurp* little busy here but what's up?", "Yep, that's me!", "^^ Hiya!", "Oh, hi there!",
"Sure, what's up?", "How can I help!", "Natsuki is busy, but I can take a message for you!",
"You were looking for Natsuki Tivastl, right?", "Sure! What's up?", "Pong!"
] ]
} }

@ -1,8 +1,11 @@
const chalk = require('chalk'); const chalk = require('chalk');
module.exports = e => { module.exports = (client, e, p) => {
console.log(`#######################################\n\n${chalk.grey('[NATS]')} >> ${chalk.hex('#78d9f8')("Well this is awkward.")}\n`); console.log(`#######################################\n\n[${chalk.grey(client.config.bot.consoleName)}] >> ${chalk.hex('#78d9f8')("Well this is awkward.")}\n`);
console.log(`${chalk.bold.redBright.underline("There was an error that killed Natsuki's process.")}\n${chalk.redBright("See available stack trace and error information below.")}\n`); console.log(`${chalk.bold.redBright.underline(`There was an error that killed ${client.utils.ps(client.config.bot.name)} process.`)}\n${chalk.redBright("See available stack trace and error information below.")}\n`);
if (p) {
client.log("This exception originates from an unhandled, uncaught promise rejection. Ya doofus.", 0, 0, 1);
}
console.error(e); console.error(e);
console.log(`\n#######################################\n\n${chalk.grey('[NATS]')} >> ${chalk.hex('#78d9f8')("Back to sleepies...")}`); console.log(`\n#######################################`);
}; };

@ -0,0 +1,13 @@
const errorhandler = require("../log/errorhandler");
const chalk = require('chalk');
module.exports = client => {
process.on('unhandledRejection', (e, p) => { //nested promise rejections like to be icky so this should catch them all
errorhandler(client, e, p);
return process.exit(1); //i guess this handler does keep the event loop running but i'll adopt a zero-tolerance policy for unhandled rejections
}); // gotta catch 'em all
process.on('exit', code => {
client.log("Back to sleepies...", {color: "#78d9f8", source: client.config.bot.consoleName}, true);
return console.log(chalk.grey(`Exit code ${chalk.white(code)}`));
});
};
Loading…
Cancel
Save