Add long message splitting

This commit is contained in:
Schuyler Cebulskie
2016-09-11 01:01:36 -04:00
parent 68879777d8
commit 7da00cf0fe
5 changed files with 86 additions and 27 deletions

View File

@@ -5,12 +5,22 @@ class MessageCreateAction extends Action {
handle(data) { handle(data) {
const client = this.client; const client = this.client;
const channel = client.channels.get(data.channel_id); const channel = client.channels.get((data instanceof Array ? data[0] : data).channel_id);
if (channel) { if (channel) {
const message = channel._cacheMessage(new Message(channel, data, client)); if (data instanceof Array) {
return { const messages = new Array(data.length);
message, for (let i = 0; i < data.length; i++) {
}; messages[i] = channel._cacheMessage(new Message(channel, data[i], client));
}
return {
messages,
};
} else {
const message = channel._cacheMessage(new Message(channel, data, client));
return {
message,
};
}
} }
return { return {

View File

@@ -1,5 +1,6 @@
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const Collection = require('../../util/Collection'); const Collection = require('../../util/Collection');
const splitMessage = require('../../util/SplitMessage');
const requireStructure = name => require(`../../structures/${name}`); const requireStructure = name => require(`../../structures/${name}`);
const User = requireStructure('User'); const User = requireStructure('User');
@@ -46,36 +47,58 @@ class RESTMethods {
}); });
} }
sendMessage(channel, content, tts, nonce, disableEveryone, file) { sendMessage(channel, content, { tts, nonce, disable_everyone, split } = {}, file = null) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const $this = this;
if (typeof content !== 'undefined') content = this.rest.client.resolver.resolveString(content); if (typeof content !== 'undefined') content = this.rest.client.resolver.resolveString(content);
if (disableEveryone || (typeof disableEveryone === 'undefined' && this.rest.client.options.disable_everyone)) { if (disable_everyone || (typeof disable_everyone === 'undefined' && this.rest.client.options.disable_everyone)) {
content = content.replace('@everyone', '@\u200beveryone').replace('@here', '@\u200bhere'); content = content.replace('@everyone', '@\u200beveryone').replace('@here', '@\u200bhere');
} }
function req() { if (split) content = splitMessage(content, typeof split === 'object' ? split : {});
$this.rest.makeRequest('post', Constants.Endpoints.channelMessages(channel.id), true, {
content, tts, nonce,
}, file)
.then(data => resolve($this.rest.client.actions.MessageCreate.handle(data).message))
.catch(reject);
}
if (channel instanceof User || channel instanceof GuildMember) { if (channel instanceof User || channel instanceof GuildMember) {
this.createDM(channel).then(chan => { this.createDM(channel).then(chan => {
channel = chan; channel = chan;
req(); this._sendMessageRequest(channel, content, file, tts, nonce, resolve, reject);
}) })
.catch(reject); .catch(reject);
} else { } else {
req(); this._sendMessageRequest(channel, content, file, tts, nonce, resolve, reject);
} }
}); });
} }
_sendMessageRequest(channel, content, file, tts, nonce, resolve, reject) {
if (content instanceof Array) {
const datas = [];
const promise = this.rest.makeRequest('post', Constants.Endpoints.channelMessages(channel.id), true, {
content: content[0], tts, nonce,
}, file);
for (let i = 1; i <= content.length; i++) {
if (i < content.length) {
promise.then(data => {
datas.push(data);
return this.rest.makeRequest('post', Constants.Endpoints.channelMessages(channel.id), true, {
content: content[i], tts, nonce,
}, file);
});
} else {
promise.then(data => {
datas.push(data);
resolve(this.rest.client.actions.MessageCreate.handle(datas).messages).catch(reject);
});
}
}
} else {
this.rest.makeRequest('post', Constants.Endpoints.channelMessages(channel.id), true, {
content, tts, nonce,
}, file)
.then(data => resolve(this.rest.client.actions.MessageCreate.handle(data).message))
.catch(reject);
}
}
deleteMessage(message) { deleteMessage(message) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('del', Constants.Endpoints.channelMessage(message.channel.id, message.id), true) this.rest.makeRequest('del', Constants.Endpoints.channelMessage(message.channel.id, message.id), true)

View File

@@ -290,7 +290,7 @@ class Message {
* Reply to a message * Reply to a message
* @param {StringResolvable} content The content for the message * @param {StringResolvable} content The content for the message
* @param {MessageOptions} [options = {}] The options to provide * @param {MessageOptions} [options = {}] The options to provide
* @returns {Promise<Message>} * @returns {Promise<Message|Message[]>}
* @example * @example
* // reply to a message * // reply to a message
* message.reply('Hey, I'm a reply!') * message.reply('Hey, I'm a reply!')
@@ -299,8 +299,15 @@ class Message {
*/ */
reply(content, options = {}) { reply(content, options = {}) {
content = this.client.resolver.resolveString(content); content = this.client.resolver.resolveString(content);
const newContent = this.guild ? `${this.author}, ${content}` : content; const prepend = this.guild ? `${this.author}, ` : '';
return this.client.rest.methods.sendMessage(this.channel, newContent, options.tts); content = `${prepend}${content}`;
if (options.split) {
if (typeof options.split !== 'object') options.split = {};
if (!options.split.prepend) options.split.prepend = prepend;
}
return this.client.rest.methods.sendMessage(this.channel, content, options);
} }
/** /**

View File

@@ -29,6 +29,7 @@ class TextBasedChannel {
* tts: false, * tts: false,
* nonce: '', * nonce: '',
* disable_everyone: false, * disable_everyone: false,
* split: false,
* }; * };
* ``` * ```
* @typedef {Object} MessageOptions * @typedef {Object} MessageOptions
@@ -38,7 +39,7 @@ class TextBasedChannel {
* Send a message to this channel * Send a message to this channel
* @param {StringResolvable} content The content to send * @param {StringResolvable} content The content to send
* @param {MessageOptions} [options={}] The options to provide * @param {MessageOptions} [options={}] The options to provide
* @returns {Promise<Message>} * @returns {Promise<Message|Message[]>}
* @example * @example
* // send a message * // send a message
* channel.sendMessage('hello!') * channel.sendMessage('hello!')
@@ -46,14 +47,14 @@ class TextBasedChannel {
* .catch(console.log); * .catch(console.log);
*/ */
sendMessage(content, options = {}) { sendMessage(content, options = {}) {
return this.client.rest.methods.sendMessage(this, content, options.tts, options.nonce, options.disable_everyone); return this.client.rest.methods.sendMessage(this, content, options);
} }
/** /**
* Send a text-to-speech message to this channel * Send a text-to-speech message to this channel
* @param {StringResolvable} content The content to send * @param {StringResolvable} content The content to send
* @param {MessageOptions} [options={}] The options to provide * @param {MessageOptions} [options={}] The options to provide
* @returns {Promise<Message>} * @returns {Promise<Message|Message[]>}
* @example * @example
* // send a TTS message * // send a TTS message
* channel.sendTTSMessage('hello!') * channel.sendTTSMessage('hello!')
@@ -61,7 +62,8 @@ class TextBasedChannel {
* .catch(console.log); * .catch(console.log);
*/ */
sendTTSMessage(content, options = {}) { sendTTSMessage(content, options = {}) {
return this.client.rest.methods.sendMessage(this, content, true, options.nonce, options.disable_everyone); Object.assign(options, { tts: true });
return this.client.rest.methods.sendMessage(this, content, options);
} }
/** /**
@@ -69,9 +71,10 @@ class TextBasedChannel {
* @param {FileResolvable} attachment The file to send * @param {FileResolvable} attachment The file to send
* @param {string} [fileName="file.jpg"] The name and extension of the file * @param {string} [fileName="file.jpg"] The name and extension of the file
* @param {StringResolvable} [content] Text message to send with the attachment * @param {StringResolvable} [content] Text message to send with the attachment
* @param {MessageOptions} [options] The options to provide
* @returns {Promise<Message>} * @returns {Promise<Message>}
*/ */
sendFile(attachment, fileName, content) { sendFile(attachment, fileName, content, options = {}) {
if (!fileName) { if (!fileName) {
if (typeof attachment === 'string') { if (typeof attachment === 'string') {
fileName = path.basename(attachment); fileName = path.basename(attachment);
@@ -83,7 +86,7 @@ class TextBasedChannel {
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.client.resolver.resolveFile(attachment).then(file => { this.client.resolver.resolveFile(attachment).then(file => {
this.client.rest.methods.sendMessage(this, content, false, undefined, false, { this.client.rest.methods.sendMessage(this, content, options, {
file, file,
name: fileName, name: fileName,
}).then(resolve).catch(reject); }).then(resolve).catch(reject);

16
src/util/SplitMessage.js Normal file
View File

@@ -0,0 +1,16 @@
module.exports = function splitMessage(text, { maxLength = 1950, char = '\n', prepend = '', append = '' } = {}) {
if (text.length <= maxLength) return text;
const splitText = text.split(char);
if (splitText.length === 1) throw new Error('Message exceeds the max length and contains no split characters.');
const messages = [''];
let msg = 0;
for (let i = 0; i < splitText.length; i++) {
if (messages[msg].length + splitText[i].length + 1 > maxLength) {
messages[msg] += append;
messages.push(prepend);
msg++;
}
messages[msg] += (messages[msg].length > 0 && messages[msg] !== prepend ? char : '') + splitText[i];
}
return messages;
};