2.1.2 • Published 6 years ago

literallyobjects v2.1.2

Weekly downloads
-
License
MIT
Repository
github
Last release
6 years ago

LiterallyObjects

LiterallyObjects is a Discord bot framework that heavily depends on JavaScript object literals to express command structures and metadata.

In-depth documentation will be provided soon, so here's some boilerplate code for now:

A 'Hello world' snippet of code:

const fs = require('fs');
const Client = require('literallyobjects');

const client = new Client({
	// Your basic discord.js ClientOptions
	messageCacheMaxSize: 50,
	messageCacheLifetime: 240,
	messageSweepInterval: 360,
	disabledEvents: ['TYPING_START'],
	disableEveryone: true
}, {
	// Configuration file
	config: require('./config.json'),

	// Language stuff
	language: {
		perms: require('./language/perms.json'),
		presences: require('./language/plays.json'),
		pasta: require('./language/pasta.json')
	},

	// The short-hand categories of your commands
	categories: {
		info: 'Help & Information',
		util: 'Utility',
		mod: 'Moderation',
		fun: 'Fun',
		img: 'String & Image Manipulation',
		config: 'Configuration',
		maint: 'Maintenance'
	},

	// The path for the database used - see LukeChilds' `keyv` package on npm for more information on this one.
	// If you actually use this example, remember to create a `data` folder and install https://github.com/recapitalverb/keyv-sqlite through npm!
	databasePath: 'sqlite://./data/database.sqlite'
});

client.on('warn', console.warn);
client.on('error', console.error);

// Login
client.login(client.config.token)
	.catch(console.error);

Loading commands:

// Bind the client object and Discord to global scope so commands can access it
Object.assign(global, {
	client,
	Discord: require('discord.js')
});

// Load all command files under the `commands` dir
fs.readdir('./commands/', (err, files) => {
	if (err) return console.error(err);
	files.map(file => {
		if (!file.endsWith('.js')) return;
		let props = require(`./commands/${file}`);
		let commandName = file.split('.')[0];
		client.commands.set(commandName, props);
	});
	client.help.build();
});

// Load all events files under the `events` dir
fs.readdir('./events/', (err, files) => {
	if (err) return console.error(err);
	files.map(file => {
		if (!file.endsWith('.js')) return;
		const event = require(`./events/${file}`);
		let eventName = file.split('.')[0];
		client.on(eventName, event);
	});
});

Editable and deletable command editing needs extra event functions to be added.

// events/message.js
module.exports = async function (msg) {
	// Handle the message
	client.handler(msg, function (content, options, traces) {
		// Reply to the user
		client.util.done(msg, content, options)
			.then(function (m) {
			// If the reply is successful, we add the output along with other info to the binds map
				if (m) {
					client.binds.set(msg.author.id, {
						input: msg.id,
						output: m,
						traces,
						timer: client.setTimeout(function () {
							client.binds.delete(msg.author.id);
						}, client.config.maxEditTime) // This removes itself from the map to limit the max time between the command execution and the next command edit / deletion
					});
				}
			});
	}, function (content, options, traces) {
		client.util.throw(msg, content, options)
			.then(function (m) {
				if (m) {
					client.binds.set(msg.author.id, {
						input: msg.id,
						output: m,
						traces,
						timer: client.setTimeout(function () {
							client.binds.delete(msg.author.id);
						}, client.config.maxEditTime)
					});
				}
			});
	});
};
// events/messageDelete.js
module.exports = function (msg) {
	let bind = client.binds.get(msg.author.id);
	// Check if the deleted message is recorded in the binds map
	if (bind && bind.input === msg.id) {
		// Delete the bind from the map and clear its timeout
		client.binds.delete(msg.author.id);
		client.clearTimeout(bind.timer);
		// Delete the output
		bind.output.delete().catch(() => undefined);
		// Remove all traces of the previous run
		if (bind.traces) bind.traces.map(function (toDelete) {
			if (toDelete.deletable) toDelete.delete().catch(() => undefined);
		});
	}
};
// events/messageUpdate.js
module.exports = function (old, msg) {
	let bind = client.binds.get(msg.author.id);
	// Check if the edited message is recorded in the binds map
	if (bind && bind.input === old.id && (bind.output.attachments.size === 0)) {
		client.binds.delete(msg.author.id);
		client.clearTimeout(bind.timer);
		if (bind.traces) bind.traces.map(function (toDelete) {
			if (toDelete.deletable) toDelete.delete().catch(() => undefined);
		});
		// We use Promise.all to wait until the client is done removing all its reactions from the message
		Promise.all(
			// Get the message reactions,
			msg.reactions.filter(function (r) {
				// filter and get only the ones the client has reacted to,
				return r.me;
			}).map(function (r) {
				// and remove them from the message, returning a resolved Promise regardless if the client did it or not
				return r.users.remove().then(function () {
					return Promise.resolve();
				}).catch(function () {
					return Promise.resolve();
				});
			})
		).then(function () {
			// After all of that, we handle the new command, edit our previous response to the new response and react to the response if needed
			client.handler(msg, function (content = '', options = {}, traces) {
				// Remove previous content / embed
				if (!options.embed) options.embed = null;
				if (options.files || (options instanceof Discord.MessageAttachment) || (Array.isArray(options) && (options[0] instanceof Discord.MessageAttachment))) {
					client.util.done(msg, content, options)
						.then(function (m) {
							// If the reply is successful, we add the output along with other info to the binds map
							if (m) {
								client.binds.set(msg.author.id, {
									input: msg.id,
									output: m,
									traces,
									timer: client.setTimeout(function () {
										client.binds.delete(msg.author.id);
									}, client.config.maxEditTime) // This removes itself from the map to limit the max time between the command execution and the next command edit / deletion
								});
							}
						});
					return;
				}
				bind.output.edit(content, options).then(function () {
					client.binds.set(msg.author.id, {
						input: msg.id,
						output: bind.output,
						traces,
						timer: client.setTimeout(function () {
							client.binds.delete(msg.author.id);
						}, client.config.maxEditTime)
					});
				});
			}, function (content = '', options = {}, traces) {
				msg.react('❌').catch(() => undefined);
				// Remove previous content / embed
				if (!options.embed) options.embed = null;
				if (options.files || (options instanceof Discord.MessageAttachment) || (Array.isArray(options) && (options[0] instanceof Discord.MessageAttachment))) {
					client.util.throw(msg, content, options)
						.then(function (m) {
							if (m) {
								client.binds.set(msg.author.id, {
									input: msg.id,
									output: m,
									traces,
									timer: client.setTimeout(function () {
										client.binds.delete(msg.author.id);
									}, client.config.maxEditTime)
								});
							}
						});
					return;
				}
				bind.output.edit(content, options).then(function () {
					client.binds.set(msg.author.id, {
						input: msg.id,
						output: bind.output,
						traces,
						timer: client.setTimeout(function () {
							client.binds.delete(msg.author.id);
						}, client.config.maxEditTime)
					});
				});
			});
		});
	} else client.emit('message', msg);
};

An example of a command file named perm.js, used for the above example. Remember to create a folder named commands and move all your command files under it.

// commands/perm.js
module.exports = {
	// The `run` function is called when the user calls the command and all conditions are satisfied (permissions, channel properties, ect.)
	run: async function (msg, p) {
		let member;
		if (p[0]) {
			member = await client.util.getMemberStrict(msg, p[0]);
			if (!member) throw new client.UserInputError('Invalid user provided. Check your spelling and try again.');
		} else member = msg.member;
		return {
			content: `All permissions for **${member.user.tag}** and their states: \n\`\`\`md\n${Object.keys(client.lang.perms).map(function (perm) {
				return (msg.channel.permissionsFor(member).has(perm, false) ? '#  TRUE | ' : '> FALSE | ') + client.lang.perms[perm];
			}).join('\n')}\`\`\``
		};
	},

	// `args` will only be used in a `help` command so that users can understand how the command functions
	args: ['mention/user ID'],
	// This number is used by the command handler to see if the user has provided enough arguments for a command
	argCount: 0,

	// The command's category
	cat: 'util',

	// Whether the command needs to be executed in a guild
	reqGuild: 'true',

	// The command's description
	desc: 'Shows all user permissions, or you can pass a mention/user ID to see that member\'s permissions.'
};
2.1.2

6 years ago

2.0.2

6 years ago

2.0.1

6 years ago

2.0.0

6 years ago

1.4.0

6 years ago

1.3.6

6 years ago

1.3.5

6 years ago

1.2.4

6 years ago

1.1.3

6 years ago

1.1.2

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago

0.1.0

6 years ago