diff --git a/src/client/actions/MessageCreate.js b/src/client/actions/MessageCreate.js index 10626179c..1280d991a 100644 --- a/src/client/actions/MessageCreate.js +++ b/src/client/actions/MessageCreate.js @@ -5,12 +5,22 @@ class MessageCreateAction extends Action { handle(data) { 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) { - const message = channel._cacheMessage(new Message(channel, data, client)); - return { - message, - }; + if (data instanceof Array) { + const messages = new Array(data.length); + 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 { diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index e878ccd61..bc588e253 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -1,5 +1,6 @@ const Constants = require('../../util/Constants'); const Collection = require('../../util/Collection'); +const splitMessage = require('../../util/SplitMessage'); const requireStructure = name => require(`../../structures/${name}`); 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) => { - const $this = this; - 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'); } - function req() { - $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 (split) content = splitMessage(content, typeof split === 'object' ? split : {}); if (channel instanceof User || channel instanceof GuildMember) { this.createDM(channel).then(chan => { channel = chan; - req(); + this._sendMessageRequest(channel, content, file, tts, nonce, resolve, reject); }) .catch(reject); } 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) { return new Promise((resolve, reject) => { this.rest.makeRequest('del', Constants.Endpoints.channelMessage(message.channel.id, message.id), true) diff --git a/src/structures/Message.js b/src/structures/Message.js index edca03498..f4bd63b54 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -290,7 +290,7 @@ class Message { * Reply to a message * @param {StringResolvable} content The content for the message * @param {MessageOptions} [options = {}] The options to provide - * @returns {Promise} + * @returns {Promise} * @example * // reply to a message * message.reply('Hey, I'm a reply!') @@ -299,8 +299,15 @@ class Message { */ reply(content, options = {}) { content = this.client.resolver.resolveString(content); - const newContent = this.guild ? `${this.author}, ${content}` : content; - return this.client.rest.methods.sendMessage(this.channel, newContent, options.tts); + const prepend = this.guild ? `${this.author}, ` : ''; + 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); } /** diff --git a/src/structures/interface/TextBasedChannel.js b/src/structures/interface/TextBasedChannel.js index 5f11e285e..4794be920 100644 --- a/src/structures/interface/TextBasedChannel.js +++ b/src/structures/interface/TextBasedChannel.js @@ -29,6 +29,7 @@ class TextBasedChannel { * tts: false, * nonce: '', * disable_everyone: false, + * split: false, * }; * ``` * @typedef {Object} MessageOptions @@ -38,7 +39,7 @@ class TextBasedChannel { * Send a message to this channel * @param {StringResolvable} content The content to send * @param {MessageOptions} [options={}] The options to provide - * @returns {Promise} + * @returns {Promise} * @example * // send a message * channel.sendMessage('hello!') @@ -46,14 +47,14 @@ class TextBasedChannel { * .catch(console.log); */ 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 * @param {StringResolvable} content The content to send * @param {MessageOptions} [options={}] The options to provide - * @returns {Promise} + * @returns {Promise} * @example * // send a TTS message * channel.sendTTSMessage('hello!') @@ -61,7 +62,8 @@ class TextBasedChannel { * .catch(console.log); */ 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 {string} [fileName="file.jpg"] The name and extension of the file * @param {StringResolvable} [content] Text message to send with the attachment + * @param {MessageOptions} [options] The options to provide * @returns {Promise} */ - sendFile(attachment, fileName, content) { + sendFile(attachment, fileName, content, options = {}) { if (!fileName) { if (typeof attachment === 'string') { fileName = path.basename(attachment); @@ -83,7 +86,7 @@ class TextBasedChannel { } return new Promise((resolve, reject) => { 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, name: fileName, }).then(resolve).catch(reject); diff --git a/src/util/SplitMessage.js b/src/util/SplitMessage.js new file mode 100644 index 000000000..3833f009a --- /dev/null +++ b/src/util/SplitMessage.js @@ -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; +};