Back to private :)

This commit is contained in:
Dragon Fire
2018-07-17 21:53:48 -04:00
parent 536e191e64
commit 11a8e26ddb
9 changed files with 14 additions and 355 deletions
+5 -16
View File
@@ -4,21 +4,20 @@
[![Donate on Patreon](https://img.shields.io/badge/patreon-donate-orange.svg)](https://www.patreon.com/dragonfire535)
[![Donate on PayPal](https://img.shields.io/badge/paypal-donate-blue.svg)](https://www.paypal.me/dragonfire535)
> This bot is not available for invite.
Xiao is a Discord bot coded in JavaScript with
[discord.js](https://discord.js.org/) using the
[Commando](https://github.com/discordjs/Commando) command framework. With nearly
300 commands, she is one of the most feature-filled bots out there.
## Invite
You can invite the bot to your server using
[this link](https://discordapp.com/oauth2/authorize?client_id=278305350804045834&scope=bot&permissions=372632641).
Be sure to also join the [home server](https://discord.gg/sbMe32W) for
information and support.
The bot is no longer available for invite. You can self-host the bot, or use her
on the [home server](https://discord.gg/sbMe32W).
## Commands (296)
## Commands (288)
### Utility:
* **prefix**: Shows or sets the command prefix.
* **eval**: Executes JavaScript code.
* **changelog**: Responds with Xiao's latest 10 commits.
* **donate**: Responds with Xiao's donation links.
@@ -26,16 +25,6 @@ information and support.
* **info**: Responds with detailed bot information.
* **invite**: Responds with Xiao's invite links.
* **ping**: Checks the bot's ping to the Discord server.
* **uptime**: Responds with how long the bot has been active.
### Command Management:
* **groups**: Lists all command groups.
* **enable**: Enables a command or command group.
* **disable**: Disables a command or command group.
* **reload**: Reloads a command or command group.
* **load**: Loads a new command.
* **unload**: Unloads a command.
### Discord Information:
+5 -13
View File
@@ -1,7 +1,7 @@
const { XIAO_TOKEN, OWNERS, XIAO_PREFIX, INVITE } = process.env;
const path = require('path');
const XiaoClient = require('./structures/Client');
const client = new XiaoClient({
const { CommandoClient } = require('discord.js-commando');
const client = new CommandoClient({
commandPrefix: XIAO_PREFIX,
owner: OWNERS.split(','),
invite: INVITE,
@@ -9,8 +9,6 @@ const client = new XiaoClient({
unknownCommandResponse: false,
disabledEvents: ['TYPING_START']
});
const { discordBots } = require('./util/BotList');
const SequelizeProvider = require('./providers/Sequelize');
const activities = require('./assets/json/activity');
client.registry
@@ -18,7 +16,6 @@ client.registry
.registerTypesIn(path.join(__dirname, 'types'))
.registerGroups([
['util', 'Utility'],
['commands', 'Command Management'],
['info', 'Discord Information'],
['random', 'Random Response'],
['single', 'Single Response'],
@@ -37,19 +34,18 @@ client.registry
])
.registerDefaultCommands({
help: false,
ping: false
ping: false,
prefix: false,
commandState: false
})
.registerCommandsIn(path.join(__dirname, 'commands'));
client.setProvider(new SequelizeProvider(client.database));
client.on('ready', () => {
console.log(`[READY] Logged in as ${client.user.tag}! (${client.user.id})`);
client.setInterval(() => {
const activity = activities[Math.floor(Math.random() * activities.length)];
client.user.setActivity(activity.text, { type: activity.type });
}, 60000);
discordBots(client);
});
client.on('disconnect', event => {
@@ -57,10 +53,6 @@ client.on('disconnect', event => {
process.exit(0);
});
client.on('guildCreate', () => discordBots(client));
client.on('guildDelete', () => discordBots(client));
client.on('commandRun', command => console.log(`[COMMAND] Ran command ${command.groupID}:${command.memberName}.`));
client.on('error', err => console.error('[ERROR]', err));
+2 -6
View File
@@ -13,13 +13,9 @@ module.exports = class InviteCommand extends Command {
});
}
async run(msg) {
const invite = await this.client.generateInvite(372632641);
run(msg) {
return msg.say(stripIndents`
To invite me to your server, use this link:
<${invite}>
Or, join my home server:
You cannot invite me to your server, but you can join my home server to use me:
${this.client.options.invite || 'Coming soon...'}
`);
}
-18
View File
@@ -1,18 +0,0 @@
const Command = require('../../structures/Command');
const { duration } = require('../../util/Util');
module.exports = class UptimeCommand extends Command {
constructor(client) {
super(client, {
name: 'uptime',
group: 'util',
memberName: 'uptime',
description: 'Responds with how long the bot has been active.',
guarded: true
});
}
run(msg) {
return msg.say(duration(this.client.uptime));
}
};
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "xiao",
"version": "84.6.0",
"version": "85.0.0",
"description": "Your personal server companion.",
"main": "Xiao.js",
"scripts": {
@@ -49,7 +49,7 @@
"zlib-sync": "^0.1.4"
},
"devDependencies": {
"eslint": "^5.0.1",
"eslint": "^5.1.0",
"eslint-config-amber": "^1.0.3",
"eslint-plugin-json": "^1.2.0"
},
-244
View File
@@ -1,244 +0,0 @@
// Credit: https://github.com/iCrawl/Tohru/blob/master/src/providers/Sequelize.js
const { SettingProvider } = require('discord.js-commando');
const Sequelize = require('sequelize');
/**
* Uses an PostgreSQL database to store settings with guilds
* @extends {SettingProvider}
*/
class SequelizeProvider extends SettingProvider {
/**
* @external PostgreSQLDatabase
* @see {@link https://www.npmjs.com/package/sequelize}
*/
/**
* @param {SQLDatabase} db - Database for the provider
*/
constructor(db) {
super();
/**
* Database that will be used for storing/retrieving settings
* @type {SQLDatabase}
*/
this.db = db;
/**
* Client that the provider is for (set once the client is ready, after using {@link CommandoClient#setProvider})
* @name SequelizeProvider#client
* @type {CommandoClient}
* @readonly
*/
Object.defineProperty(this, 'client', { value: null, writable: true });
/**
* Settings cached in memory, mapped by guild ID (or 'global')
* @type {Map}
* @private
*/
this.settings = new Map();
/**
* Listeners on the Client, mapped by the event name
* @type {Map}
* @private
*/
this.listeners = new Map();
/**
* Sequelize Model Object
* @type {SequelizeModel}
* @private
*/
this.model = this.db.define('settings', {
guild: {
type: Sequelize.BIGINT,
allowNull: false,
unique: true,
primaryKey: true
},
settings: { type: Sequelize.TEXT }
}, { freezeTableName: true, timestamps: false });
/**
* @external SequelizeModel
* @see {@link http://docs.sequelizejs.com/en/latest/api/model/}
*/
}
async init(client) {
this.client = client;
await this.db.sync();
// Load all settings
const rows = await this.model.findAll();
for (const row of rows) {
let settings;
try {
settings = JSON.parse(row.dataValues.settings);
} catch (err) {
client.emit('warn', `SequelizeProvider couldn't parse the settings stored for guild ${row.dataValues.guild}.`);
continue;
}
const guild = row.dataValues.guild !== '0' ? row.dataValues.guild : 'global';
this.settings.set(guild, settings);
if (guild !== 'global' && !client.guilds.has(row.dataValues.guild)) continue;
this.setupGuild(guild, settings);
}
// Listen for changes
this.listeners
.set('commandPrefixChange', (guild, prefix) => this.set(guild, 'prefix', prefix))
.set('commandStatusChange', (guild, command, enabled) => this.set(guild, `cmd-${command.name}`, enabled))
.set('groupStatusChange', (guild, group, enabled) => this.set(guild, `grp-${group.id}`, enabled))
.set('guildCreate', guild => {
const settings = this.settings.get(guild.id);
if (!settings) return;
this.setupGuild(guild.id, settings);
})
.set('commandRegister', command => {
for (const [guild, settings] of this.settings) {
if (guild !== 'global' && !client.guilds.has(guild)) continue;
this.setupGuildCommand(client.guilds.get(guild), command, settings);
}
})
.set('groupRegister', group => {
for (const [guild, settings] of this.settings) {
if (guild !== 'global' && !client.guilds.has(guild)) continue;
this.setupGuildGroup(client.guilds.get(guild), group, settings);
}
});
for (const [event, listener] of this.listeners) client.on(event, listener);
}
destroy() {
// Remove all listeners from the client
for (const [event, listener] of this.listeners) this.client.removeListener(event, listener);
this.listeners.clear();
}
get(guild, key, defVal) {
const settings = this.settings.get(this.constructor.getGuildID(guild));
return settings ? typeof settings[key] !== 'undefined' ? settings[key] : defVal : defVal;
}
async set(guild, key, val) {
guild = this.constructor.getGuildID(guild);
let settings = this.settings.get(guild);
if (!settings) {
settings = {};
this.settings.set(guild, settings);
}
settings[key] = val;
await this.model.upsert(
{ guild: guild !== 'global' ? guild : '0', settings: JSON.stringify(settings) }
);
if (guild === 'global') this.updateOtherShards(key, val);
return val;
}
async remove(guild, key) {
guild = this.constructor.getGuildID(guild);
const settings = this.settings.get(guild);
if (!settings || typeof settings[key] === 'undefined') return undefined;
const val = settings[key];
settings[key] = undefined;
await this.model.upsert(
{ guild: guild !== 'global' ? guild : '0', settings: JSON.stringify(settings) }
);
if (guild === 'global') this.updateOtherShards(key, undefined);
return val;
}
async clear(guild) {
guild = this.constructor.getGuildID(guild);
if (!this.settings.has(guild)) return;
this.settings.delete(guild);
await this.model.destroy({ where: { guild: guild !== 'global' ? guild : '0' } });
}
/**
* Loads all settings for a guild
* @param {string} guild - Guild ID to load the settings of (or 'global')
* @param {Object} settings - Settings to load
* @private
*/
setupGuild(guild, settings) {
if (typeof guild !== 'string') throw new TypeError('The guild must be a guild ID or "global".');
guild = this.client.guilds.get(guild) || null;
// Load the command prefix
if (typeof settings.prefix !== 'undefined') {
if (guild) guild._commandPrefix = settings.prefix;
else this.client._commandPrefix = settings.prefix;
}
// Load all command/group statuses
for (const command of this.client.registry.commands.values()) this.setupGuildCommand(guild, command, settings);
for (const group of this.client.registry.groups.values()) this.setupGuildGroup(guild, group, settings);
}
/**
* Sets up a command's status in a guild from the guild's settings
* @param {?Guild} guild - Guild to set the status in
* @param {Command} command - Command to set the status of
* @param {Object} settings - Settings of the guild
* @private
*/
setupGuildCommand(guild, command, settings) {
if (typeof settings[`cmd-${command.name}`] === 'undefined') return;
if (guild) {
if (!guild._commandsEnabled) guild._commandsEnabled = {};
guild._commandsEnabled[command.name] = settings[`cmd-${command.name}`];
} else {
command._globalEnabled = settings[`cmd-${command.name}`];
}
}
/**
* Sets up a group's status in a guild from the guild's settings
* @param {?Guild} guild - Guild to set the status in
* @param {CommandGroup} group - Group to set the status of
* @param {Object} settings - Settings of the guild
* @private
*/
setupGuildGroup(guild, group, settings) {
if (typeof settings[`grp-${group.id}`] === 'undefined') return;
if (guild) {
if (!guild._groupsEnabled) guild._groupsEnabled = {};
guild._groupsEnabled[group.id] = settings[`grp-${group.id}`];
} else {
group._globalEnabled = settings[`grp-${group.id}`];
}
}
/**
* Updates a global setting on all other shards if using the {@link ShardingManager}.
* @param {string} key - Key of the setting to update
* @param {*} val - Value of the setting
* @private
*/
updateOtherShards(key, val) {
if (!this.client.shard) return;
key = JSON.stringify(key);
val = typeof val !== 'undefined' ? JSON.stringify(val) : 'undefined';
this.client.shard.broadcastEval(`
if(this.shard.id !== ${this.client.shard.id} && this.provider && this.provider.settings) {
let global = this.provider.settings.get('global');
if (!global) {
global = {};
this.provider.settings.set('global', global)
}
global[${key}] = ${val};
}
`);
}
}
module.exports = SequelizeProvider;
-13
View File
@@ -1,13 +0,0 @@
const { CommandoClient } = require('discord.js-commando');
const Database = require('../structures/PostgreSQL');
class XiaoClient extends CommandoClient {
constructor(options) {
super(options);
this.database = Database.db;
Database.start();
}
}
module.exports = XiaoClient;
-23
View File
@@ -1,23 +0,0 @@
const Sequelize = require('sequelize');
const { DB_URL } = process.env;
const db = new Sequelize(DB_URL, { logging: false, operatorsAliases: false });
class PostgreSQL {
static get db() {
return db;
}
static async start() {
try {
await db.authenticate();
console.log('[DATABASE] Connection established! Syncing...');
await db.sync();
console.log('[DATABASE] Database sync complete!');
} catch (err) {
console.error('[DATABASE] Unable to connect to database:', err);
setTimeout(() => PostgreSQL.start(), 5000);
}
}
}
module.exports = PostgreSQL;
-20
View File
@@ -1,20 +0,0 @@
const request = require('node-superfetch');
const { DISCORD_BOTS_TOKEN } = process.env;
class BotListUtil {
static async discordBots(client) {
try {
const { body } = await request
.post(`https://bots.discord.pw/api/bots/${client.user.id}/stats`)
.set({ Authorization: DISCORD_BOTS_TOKEN })
.send({ server_count: client.guilds.size });
console.log('[DISCORD BOTS] Posted to Discord Bots.');
return body;
} catch (err) {
console.error('[DISCORD BOTS] Failed to post to Discord Bots.', err);
return err;
}
}
}
module.exports = BotListUtil;