mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-19 04:53:30 +01:00
Merge branch '11.1-dev' into stable
This commit is contained in:
42
.gitignore
vendored
42
.gitignore
vendored
@@ -1,21 +1,21 @@
|
|||||||
# Packages
|
# Packages
|
||||||
node_modules/
|
node_modules/
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
# Log files
|
# Log files
|
||||||
logs/
|
logs/
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# Authentication
|
# Authentication
|
||||||
test/auth.json
|
test/auth.json
|
||||||
test/auth.js
|
test/auth.js
|
||||||
docs/deploy/deploy_key
|
docs/deploy/deploy_key
|
||||||
docs/deploy/deploy_key.pub
|
docs/deploy/deploy_key.pub
|
||||||
deploy/deploy_key
|
deploy/deploy_key
|
||||||
deploy/deploy_key.pub
|
deploy/deploy_key.pub
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
.tmp/
|
.tmp/
|
||||||
.vscode/
|
.vscode/
|
||||||
docs/docs.json
|
docs/docs.json
|
||||||
webpack/
|
webpack/
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
{
|
{
|
||||||
"ecmaVersion": 6,
|
"ecmaVersion": 7,
|
||||||
"libs": [],
|
"libs": [],
|
||||||
|
"loadEagerly": [
|
||||||
|
"./src/*.js"
|
||||||
|
],
|
||||||
|
"dontLoad": [
|
||||||
|
"node_modules/**"
|
||||||
|
],
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"node": {
|
"es_modules": {},
|
||||||
"dontLoad": "node_modules/**",
|
"node": {},
|
||||||
"load": "",
|
"doc_comment": {
|
||||||
"modules": ""
|
"fullDocs": true,
|
||||||
|
"strong": true
|
||||||
|
},
|
||||||
|
"webpack": {
|
||||||
|
"configPath": "./webpack.config.js",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
.travis.yml
36
.travis.yml
@@ -1,16 +1,20 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "6"
|
- "6"
|
||||||
- "7"
|
- "7"
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- node_modules
|
- node_modules
|
||||||
install: npm install
|
install: npm install
|
||||||
script:
|
script: bash ./deploy/test.sh
|
||||||
- bash ./deploy/deploy.sh
|
jobs:
|
||||||
env:
|
include:
|
||||||
global:
|
- stage: build
|
||||||
- ENCRYPTION_LABEL: "af862fa96d3e"
|
node_js: "6"
|
||||||
- COMMIT_AUTHOR_EMAIL: "amishshah.2k@gmail.com"
|
script: bash ./deploy/deploy.sh
|
||||||
dist: trusty
|
env:
|
||||||
sudo: false
|
global:
|
||||||
|
- ENCRYPTION_LABEL: "af862fa96d3e"
|
||||||
|
- COMMIT_AUTHOR_EMAIL: "amishshah.2k@gmail.com"
|
||||||
|
dist: trusty
|
||||||
|
sudo: false
|
||||||
|
|||||||
9
browser.js
Normal file
9
browser.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const browser = typeof window !== 'undefined';
|
||||||
|
const webpack = !!process.env.__DISCORD_WEBPACK__;
|
||||||
|
|
||||||
|
const Discord = require('./');
|
||||||
|
|
||||||
|
module.exports = Discord;
|
||||||
|
if (browser && webpack) window.Discord = Discord; // eslint-disable-line no-undef
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
else if (!browser) console.warn('Warning: Attempting to use browser version of Discord.js in a non-browser environment!');
|
||||||
@@ -3,15 +3,7 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
function tests {
|
|
||||||
npm run lint
|
|
||||||
npm run docs:test
|
|
||||||
VERSIONED=false npm run webpack
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function build {
|
function build {
|
||||||
npm run lint
|
|
||||||
npm run docs
|
npm run docs
|
||||||
VERSIONED=false npm run webpack
|
VERSIONED=false npm run webpack
|
||||||
}
|
}
|
||||||
@@ -22,10 +14,10 @@ if [[ "$TRAVIS_BRANCH" == revert-* ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For PRs, only run tests
|
# For PRs, do nothing
|
||||||
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
||||||
echo -e "\e[36m\e[1mBuild triggered for PR #${TRAVIS_PULL_REQUEST} to branch \"${TRAVIS_BRANCH}\" - only running tests."
|
echo -e "\e[36m\e[1mBuild triggered for PR #${TRAVIS_PULL_REQUEST} to branch \"${TRAVIS_BRANCH}\" - doing nothing."
|
||||||
tests
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Figure out the source of the build
|
# Figure out the source of the build
|
||||||
@@ -39,10 +31,10 @@ else
|
|||||||
SOURCE_TYPE="branch"
|
SOURCE_TYPE="branch"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For Node != 6, only run tests
|
# For Node != 6, do nothing
|
||||||
if [ "$TRAVIS_NODE_VERSION" != "6" ]; then
|
if [ "$TRAVIS_NODE_VERSION" != "6" ]; then
|
||||||
echo -e "\e[36m\e[1mBuild triggered with Node v${TRAVIS_NODE_VERSION} - only running tests."
|
echo -e "\e[36m\e[1mBuild triggered with Node v${TRAVIS_NODE_VERSION} - doing nothing."
|
||||||
tests
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
build
|
build
|
||||||
|
|||||||
34
deploy/test.sh
Normal file
34
deploy/test.sh
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function tests {
|
||||||
|
npm run lint
|
||||||
|
npm run docs:test
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# For revert branches, do nothing
|
||||||
|
if [[ "$TRAVIS_BRANCH" == revert-* ]]; then
|
||||||
|
echo -e "\e[36m\e[1mTest triggered for reversion branch \"${TRAVIS_BRANCH}\" - doing nothing."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For PRs
|
||||||
|
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
||||||
|
echo -e "\e[36m\e[1mTest triggered for PR #${TRAVIS_PULL_REQUEST} to branch \"${TRAVIS_BRANCH}\" - only running tests."
|
||||||
|
tests
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Figure out the source of the test
|
||||||
|
if [ -n "$TRAVIS_TAG" ]; then
|
||||||
|
echo -e "\e[36m\e[1mTest triggered for tag \"${TRAVIS_TAG}\"."
|
||||||
|
else
|
||||||
|
echo -e "\e[36m\e[1mTest triggered for branch \"${TRAVIS_BRANCH}\"."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Node != 6
|
||||||
|
if [ "$TRAVIS_NODE_VERSION" != "6" ]; then
|
||||||
|
echo -e "\e[36m\e[1mTest triggered with Node v${TRAVIS_NODE_VERSION} - only running tests."
|
||||||
|
tests
|
||||||
|
fi
|
||||||
@@ -1 +1 @@
|
|||||||
## [View the documentation here.](https://discord.js.org/#/docs)
|
## [View the documentation here.](https://discord.js.org/#/docs)
|
||||||
|
|||||||
@@ -19,11 +19,7 @@ client.on('ready', () => {
|
|||||||
|
|
||||||
// Create an event listener for new guild members
|
// Create an event listener for new guild members
|
||||||
client.on('guildMemberAdd', member => {
|
client.on('guildMemberAdd', member => {
|
||||||
// Send the message to the guilds default channel (usually #general), mentioning the member
|
// Send the message to a designated channel on a server:
|
||||||
member.guild.defaultChannel.send(`Welcome to the server, ${member}!`);
|
|
||||||
|
|
||||||
// If you want to send the message to a designated channel on a server instead
|
|
||||||
// you can do the following:
|
|
||||||
const channel = member.guild.channels.find('name', 'member-log');
|
const channel = member.guild.channels.find('name', 'member-log');
|
||||||
// Do nothing if the channel wasn't found on this server
|
// Do nothing if the channel wasn't found on this server
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# Version 11.2.0
|
||||||
|
v11.2.0 fixes a lot of bugs we encountered along the 11.1.0 release, as well as support for new features such as Message Attachments and UserGuildSettings.
|
||||||
|
See [the changelog](https://github.com/hydrabolt/discord.js/releases/tag/11.2.0) for a full list of changes, including information about deprecations.
|
||||||
|
|
||||||
# Version 11.1.0
|
# Version 11.1.0
|
||||||
v11.1.0 features improved voice and gateway stability, as well as support for new features such as audit logs and searching for messages.
|
v11.1.0 features improved voice and gateway stability, as well as support for new features such as audit logs and searching for messages.
|
||||||
See [the changelog](https://github.com/hydrabolt/discord.js/releases/tag/11.1.0) for a full list of changes, including
|
See [the changelog](https://github.com/hydrabolt/discord.js/releases/tag/11.1.0) for a full list of changes, including
|
||||||
@@ -118,9 +122,9 @@ The guild parameter that has been dropped from the guild-related events can stil
|
|||||||
|
|
||||||
## Dates and timestamps
|
## Dates and timestamps
|
||||||
All dates/timestamps on the structures have been refactored to have a consistent naming scheme and availability.
|
All dates/timestamps on the structures have been refactored to have a consistent naming scheme and availability.
|
||||||
All of them are named similarly to this:
|
All of them are named similarly to this:
|
||||||
**Date:** `Message.createdAt`
|
**Date:** `Message.createdAt`
|
||||||
**Timestamp:** `Message.createdTimestamp`
|
**Timestamp:** `Message.createdTimestamp`
|
||||||
See the docs for each structure to see which date/timestamps are available on them.
|
See the docs for each structure to see which date/timestamps are available on them.
|
||||||
|
|
||||||
|
|
||||||
@@ -149,7 +153,7 @@ A couple more important details:
|
|||||||
* `Client.servers.length` ==> `client.guilds.size` (all instances of `server` are now `guild`)
|
* `Client.servers.length` ==> `client.guilds.size` (all instances of `server` are now `guild`)
|
||||||
|
|
||||||
## No more callbacks!
|
## No more callbacks!
|
||||||
Version 9 eschews callbacks in favour of Promises. This means all code relying on callbacks must be changed.
|
Version 9 eschews callbacks in favour of Promises. This means all code relying on callbacks must be changed.
|
||||||
For example, the following code:
|
For example, the following code:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Welcome!
|
# Welcome!
|
||||||
Welcome to the discord.js v11.1.0 documentation.
|
Welcome to the discord.js v11.2.0 documentation.
|
||||||
v11.1.0 features improved voice and gateway stability, as well as support for new features such as audit logs and searching for messages.
|
v11.2.0 fixes a lot of bugs we encountered along the 11.1.0 release, as well as support for new features such as Message Attachments and UserGuildSettings.
|
||||||
|
|
||||||
## About
|
## About
|
||||||
discord.js is a powerful [node.js](https://nodejs.org) module that allows you to interact with the
|
discord.js is a powerful [node.js](https://nodejs.org) module that allows you to interact with the
|
||||||
@@ -30,11 +30,11 @@ discord.js is a powerful [node.js](https://nodejs.org) module that allows you to
|
|||||||
- 100% coverage of the Discord API
|
- 100% coverage of the Discord API
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
**Node.js 6.0.0 or newer is required.**
|
**Node.js 6.0.0 or newer is required.**
|
||||||
Ignore any warnings about unmet peer dependencies, as they're all optional.
|
Ignore any warnings about unmet peer dependencies, as they're all optional.
|
||||||
|
|
||||||
Without voice support: `npm install discord.js --save`
|
Without voice support: `npm install discord.js --save`
|
||||||
With voice support ([node-opus](https://www.npmjs.com/package/node-opus)): `npm install discord.js node-opus --save`
|
With voice support ([node-opus](https://www.npmjs.com/package/node-opus)): `npm install discord.js node-opus --save`
|
||||||
With voice support ([opusscript](https://www.npmjs.com/package/opusscript)): `npm install discord.js opusscript --save`
|
With voice support ([opusscript](https://www.npmjs.com/package/opusscript)): `npm install discord.js opusscript --save`
|
||||||
|
|
||||||
### Audio engines
|
### Audio engines
|
||||||
@@ -79,8 +79,8 @@ client.login('your token');
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||||
[documentation](https://discord.js.org/#/docs).
|
[documentation](https://discord.js.org/#/docs).
|
||||||
See [the contribution guide](https://github.com/hydrabolt/discord.js/blob/master/CONTRIBUTING.md) if you'd like to submit a PR.
|
See [the contribution guide](https://github.com/hydrabolt/discord.js/blob/master/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Voice in discord.js can be used for many things, such as music bots, recording o
|
|||||||
In discord.js, you can use voice by connecting to a `VoiceChannel` to obtain a `VoiceConnection`, where you can start streaming and receiving audio.
|
In discord.js, you can use voice by connecting to a `VoiceChannel` to obtain a `VoiceConnection`, where you can start streaming and receiving audio.
|
||||||
|
|
||||||
To get started, make sure you have:
|
To get started, make sure you have:
|
||||||
* ffmpeg - `npm install --global ffmpeg-binaries`
|
* ffmpeg - `npm install ffmpeg-binaries`
|
||||||
* an opus encoder, choose one from below:
|
* an opus encoder, choose one from below:
|
||||||
* `npm install opusscript`
|
* `npm install opusscript`
|
||||||
* `npm install node-opus`
|
* `npm install node-opus`
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ The usage of the API isn't any different from using it in Node.js.
|
|||||||
client.on('message', msg => {
|
client.on('message', msg => {
|
||||||
const guildTag = msg.channel.type === 'text' ? `[${msg.guild.name}]` : '[DM]';
|
const guildTag = msg.channel.type === 'text' ? `[${msg.guild.name}]` : '[DM]';
|
||||||
const channelTag = msg.channel.type === 'text' ? `[#${msg.channel.name}]` : '';
|
const channelTag = msg.channel.type === 'text' ? `[#${msg.channel.name}]` : '';
|
||||||
console.log(`${guildTag}${channelTag} ${msg.author.username}#${msg.author.discriminator}: ${msg.content}`);
|
console.log(`${guildTag}${channelTag} ${msg.author.tag}: ${msg.content}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.login('some crazy token');
|
client.login('some crazy token');
|
||||||
|
|||||||
26
package.json
26
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "discord.js",
|
"name": "discord.js",
|
||||||
"version": "11.1.0",
|
"version": "11.2.0",
|
||||||
"description": "A powerful library for interacting with the Discord API",
|
"description": "A powerful library for interacting with the Discord API",
|
||||||
"main": "./src/index",
|
"main": "./src/index",
|
||||||
"types": "./typings/index.d.ts",
|
"types": "./typings/index.d.ts",
|
||||||
@@ -34,26 +34,26 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"long": "^3.2.0",
|
"long": "^3.2.0",
|
||||||
"prism-media": "^0.0.1",
|
"prism-media": "^0.0.1",
|
||||||
"snekfetch": "^3.1.0",
|
"snekfetch": "^3.3.0",
|
||||||
"tweetnacl": "^0.14.0",
|
"tweetnacl": "^1.0.0",
|
||||||
"ws": "^2.0.0"
|
"ws": "^3.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"bufferutil": "^3.0.0",
|
"bufferutil": "^3.0.2",
|
||||||
"erlpack": "hammerandchisel/erlpack",
|
"erlpack": "hammerandchisel/erlpack",
|
||||||
"node-opus": "^0.2.5",
|
"node-opus": "^0.2.6",
|
||||||
"opusscript": "^0.0.3",
|
"opusscript": "^0.0.3",
|
||||||
"sodium": "^2.0.1",
|
"sodium": "^2.0.1",
|
||||||
"libsodium-wrappers": "^0.5.1",
|
"libsodium-wrappers": "^0.5.4",
|
||||||
"uws": "^0.14.1"
|
"uws": "^0.14.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^7.0.0",
|
"@types/node": "^7.0.43",
|
||||||
"discord.js-docgen": "hydrabolt/discord.js-docgen",
|
"discord.js-docgen": "hydrabolt/discord.js-docgen",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^4.6.0",
|
||||||
"parallel-webpack": "^1.6.0",
|
"parallel-webpack": "^2.1.0",
|
||||||
"uglify-js": "mishoo/UglifyJS2#harmony",
|
"uglifyjs-webpack-plugin": "^1.0.0-beta.1",
|
||||||
"webpack": "^2.2.0"
|
"webpack": "^3.5.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
const os = require('os');
|
const EventEmitter = require('events');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
|
||||||
const Constants = require('../util/Constants');
|
const Constants = require('../util/Constants');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const Util = require('../util/Util');
|
const Util = require('../util/Util');
|
||||||
@@ -120,6 +119,7 @@ class Client extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
this.presences = new Collection();
|
this.presences = new Collection();
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'token', { writable: true });
|
||||||
if (!this.token && 'CLIENT_TOKEN' in process.env) {
|
if (!this.token && 'CLIENT_TOKEN' in process.env) {
|
||||||
/**
|
/**
|
||||||
* Authorization token for the logged in user/bot
|
* Authorization token for the logged in user/bot
|
||||||
@@ -249,7 +249,7 @@ class Client extends EventEmitter {
|
|||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get browser() {
|
get browser() {
|
||||||
return os.platform() === 'browser';
|
return typeof window !== 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -419,9 +419,9 @@ class Client extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
setTimeout(fn, delay, ...args) {
|
setTimeout(fn, delay, ...args) {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
fn();
|
fn(...args);
|
||||||
this._timeouts.delete(timeout);
|
this._timeouts.delete(timeout);
|
||||||
}, delay, ...args);
|
}, delay);
|
||||||
this._timeouts.add(timeout);
|
this._timeouts.add(timeout);
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class ClientDataResolver {
|
|||||||
/**
|
/**
|
||||||
* Data that resolves to give a User object. This can be:
|
* Data that resolves to give a User object. This can be:
|
||||||
* * A User object
|
* * A User object
|
||||||
* * A user ID
|
* * A Snowflake
|
||||||
* * A Message object (resolves to the message author)
|
* * A Message object (resolves to the message author)
|
||||||
* * A Guild object (owner of the guild)
|
* * A Guild object (owner of the guild)
|
||||||
* * A GuildMember object
|
* * A GuildMember object
|
||||||
@@ -65,7 +65,7 @@ class ClientDataResolver {
|
|||||||
/**
|
/**
|
||||||
* Data that resolves to give a Guild object. This can be:
|
* Data that resolves to give a Guild object. This can be:
|
||||||
* * A Guild object
|
* * A Guild object
|
||||||
* * A Guild ID
|
* * A Snowflake
|
||||||
* @typedef {Guild|Snowflake} GuildResolvable
|
* @typedef {Guild|Snowflake} GuildResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ class ClientDataResolver {
|
|||||||
* * A Channel object
|
* * A Channel object
|
||||||
* * A Message object (the channel the message was sent in)
|
* * A Message object (the channel the message was sent in)
|
||||||
* * A Guild object (the #general channel)
|
* * A Guild object (the #general channel)
|
||||||
* * A channel ID
|
* * A Snowflake
|
||||||
* @typedef {Channel|Guild|Message|Snowflake} ChannelResolvable
|
* @typedef {Channel|Guild|Message|Snowflake} ChannelResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -174,6 +174,20 @@ class ClientDataResolver {
|
|||||||
return String(data);
|
return String(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image.
|
||||||
|
* @param {BufferResolvable|Base64Resolvable} image The image to be resolved
|
||||||
|
* @returns {Promise<?string>}
|
||||||
|
*/
|
||||||
|
resolveImage(image) {
|
||||||
|
if (!image) return Promise.resolve(null);
|
||||||
|
if (typeof image === 'string' && image.startsWith('data:')) {
|
||||||
|
return Promise.resolve(image);
|
||||||
|
}
|
||||||
|
return this.resolveFile(image).then(this.resolveBase64);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that resolves to give a Base64 string, typically for image uploading. This can be:
|
* Data that resolves to give a Base64 string, typically for image uploading. This can be:
|
||||||
* * A Buffer
|
* * A Buffer
|
||||||
@@ -192,19 +206,25 @@ class ClientDataResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that can be resolved to give a Buffer. This can be:
|
* Data that can be resolved to give a Buffer. This can be:
|
||||||
* * A Buffer
|
* * A Buffer
|
||||||
* * The path to a local file
|
* * The path to a local file
|
||||||
* * A URL
|
* * A URL
|
||||||
* @typedef {string|Buffer} BufferResolvable
|
* * A Stream
|
||||||
*/
|
* @typedef {string|Buffer} BufferResolvable
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a BufferResolvable to a Buffer.
|
* @external Stream
|
||||||
* @param {BufferResolvable} resource The buffer resolvable to resolve
|
* @see {@link https://nodejs.org/api/stream.html}
|
||||||
* @returns {Promise<Buffer>}
|
*/
|
||||||
*/
|
|
||||||
resolveBuffer(resource) {
|
/**
|
||||||
|
* Resolves a BufferResolvable to a Buffer.
|
||||||
|
* @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve
|
||||||
|
* @returns {Promise<Buffer>}
|
||||||
|
*/
|
||||||
|
resolveFile(resource) {
|
||||||
if (resource instanceof Buffer) return Promise.resolve(resource);
|
if (resource instanceof Buffer) return Promise.resolve(resource);
|
||||||
if (this.client.browser && resource instanceof ArrayBuffer) return Promise.resolve(convertToBuffer(resource));
|
if (this.client.browser && resource instanceof ArrayBuffer) return Promise.resolve(convertToBuffer(resource));
|
||||||
|
|
||||||
@@ -212,11 +232,11 @@ class ClientDataResolver {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (/^https?:\/\//.test(resource)) {
|
if (/^https?:\/\//.test(resource)) {
|
||||||
snekfetch.get(resource)
|
snekfetch.get(resource)
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
if (err) return reject(err);
|
if (err) return reject(err);
|
||||||
if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
|
if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
|
||||||
return resolve(res.body);
|
return resolve(res.body);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const file = path.resolve(resource);
|
const file = path.resolve(resource);
|
||||||
fs.stat(file, (err, stats) => {
|
fs.stat(file, (err, stats) => {
|
||||||
@@ -229,6 +249,13 @@ class ClientDataResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if (resource.pipe && typeof resource.pipe === 'function') {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const buffers = [];
|
||||||
|
resource.once('error', reject);
|
||||||
|
resource.on('data', data => buffers.push(data));
|
||||||
|
resource.once('end', () => resolve(Buffer.concat(buffers)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(new TypeError('The resource must be a string or Buffer.'));
|
return Promise.reject(new TypeError('The resource must be a string or Buffer.'));
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class ClientManager {
|
|||||||
const gateway = `${res.url}/?v=${protocolVersion}&encoding=${WebSocketConnection.ENCODING}`;
|
const gateway = `${res.url}/?v=${protocolVersion}&encoding=${WebSocketConnection.ENCODING}`;
|
||||||
this.client.emit(Constants.Events.DEBUG, `Using gateway ${gateway}`);
|
this.client.emit(Constants.Events.DEBUG, `Using gateway ${gateway}`);
|
||||||
this.client.ws.connect(gateway);
|
this.client.ws.connect(gateway);
|
||||||
this.client.ws.once('close', event => {
|
this.client.ws.connection.once('close', event => {
|
||||||
if (event.code === 4004) reject(new Error(Constants.Errors.BAD_LOGIN));
|
if (event.code === 4004) reject(new Error(Constants.Errors.BAD_LOGIN));
|
||||||
if (event.code === 4010) reject(new Error(Constants.Errors.INVALID_SHARD));
|
if (event.code === 4010) reject(new Error(Constants.Errors.INVALID_SHARD));
|
||||||
if (event.code === 4011) reject(new Error(Constants.Errors.SHARDING_REQUIRED));
|
if (event.code === 4011) reject(new Error(Constants.Errors.SHARDING_REQUIRED));
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ class WebhookClient extends Webhook {
|
|||||||
*/
|
*/
|
||||||
setTimeout(fn, delay, ...args) {
|
setTimeout(fn, delay, ...args) {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
fn();
|
fn(...args);
|
||||||
this._timeouts.delete(timeout);
|
this._timeouts.delete(timeout);
|
||||||
}, delay, ...args);
|
}, delay);
|
||||||
this._timeouts.add(timeout);
|
this._timeouts.add(timeout);
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const snekfetch = require('snekfetch');
|
|||||||
const Constants = require('../../util/Constants');
|
const Constants = require('../../util/Constants');
|
||||||
|
|
||||||
class APIRequest {
|
class APIRequest {
|
||||||
constructor(rest, method, path, auth, data, files) {
|
constructor(rest, method, path, auth, data, files, reason) {
|
||||||
this.rest = rest;
|
this.rest = rest;
|
||||||
this.client = rest.client;
|
this.client = rest.client;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
@@ -11,6 +11,7 @@ class APIRequest {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
this.files = files;
|
this.files = files;
|
||||||
this.route = this.getRoute(this.path);
|
this.route = this.getRoute(this.path);
|
||||||
|
this.reason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoute(url) {
|
getRoute(url) {
|
||||||
@@ -36,6 +37,7 @@ class APIRequest {
|
|||||||
const API = `${this.client.options.http.host}/api/v${this.client.options.http.version}`;
|
const API = `${this.client.options.http.host}/api/v${this.client.options.http.version}`;
|
||||||
const request = snekfetch[this.method](`${API}${this.path}`);
|
const request = snekfetch[this.method](`${API}${this.path}`);
|
||||||
if (this.auth) request.set('Authorization', this.getAuth());
|
if (this.auth) request.set('Authorization', this.getAuth());
|
||||||
|
if (this.reason) request.set('X-Audit-Log-Reason', encodeURIComponent(this.reason));
|
||||||
if (!this.rest.client.browser) request.set('User-Agent', this.rest.userAgentManager.userAgent);
|
if (!this.rest.client.browser) request.set('User-Agent', this.rest.userAgentManager.userAgent);
|
||||||
if (this.files) {
|
if (this.files) {
|
||||||
for (const file of this.files) if (file && file.file) request.attach(file.name, file.file, file.name);
|
for (const file of this.files) if (file && file.file) request.attach(file.name, file.file, file.name);
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Represents an error from the Discord API.
|
* Represents an error from the Discord API.
|
||||||
|
* @extends Error
|
||||||
*/
|
*/
|
||||||
class DiscordAPIError extends Error {
|
class DiscordAPIError extends Error {
|
||||||
constructor(error) {
|
constructor(path, error) {
|
||||||
super();
|
super();
|
||||||
const flattened = error.errors ? `\n${this.constructor.flattenErrors(error.errors).join('\n')}` : '';
|
const flattened = this.constructor.flattenErrors(error.errors || error).join('\n');
|
||||||
this.name = 'DiscordAPIError';
|
this.name = 'DiscordAPIError';
|
||||||
this.message = `${error.message}${flattened}`;
|
this.message = error.message && flattened ? `${error.message}\n${flattened}` : error.message || flattened;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path of the request relative to the HTTP endpoint
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.path = path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP error code returned by Discord
|
* HTTP error code returned by Discord
|
||||||
@@ -18,15 +25,23 @@ class DiscordAPIError extends Error {
|
|||||||
/**
|
/**
|
||||||
* Flattens an errors object returned from the API into an array.
|
* Flattens an errors object returned from the API into an array.
|
||||||
* @param {Object} obj Discord errors object
|
* @param {Object} obj Discord errors object
|
||||||
* @param {string} [key] idklol
|
* @param {string} [key] Used internally to determine key names of nested fields
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
static flattenErrors(obj, key = '') {
|
static flattenErrors(obj, key = '') {
|
||||||
let messages = [];
|
let messages = [];
|
||||||
|
|
||||||
for (const k of Object.keys(obj)) {
|
for (const k of Object.keys(obj)) {
|
||||||
|
if (k === 'message') continue;
|
||||||
const newKey = key ? isNaN(k) ? `${key}.${k}` : `${key}[${k}]` : k;
|
const newKey = key ? isNaN(k) ? `${key}.${k}` : `${key}[${k}]` : k;
|
||||||
|
|
||||||
if (obj[k]._errors) {
|
if (obj[k]._errors) {
|
||||||
messages.push(`${newKey}: ${obj[k]._errors.map(e => e.message).join(' ')}`);
|
messages.push(`${newKey}: ${obj[k]._errors.map(e => e.message).join(' ')}`);
|
||||||
|
} else if (obj[k].code || obj[k].message) {
|
||||||
|
messages.push(`${obj[k].code ? `${obj[k].code}: ` : ''}: ${obj[k].message}`.trim());
|
||||||
|
} else if (typeof obj[k] === 'string') {
|
||||||
|
messages.push(obj[k]);
|
||||||
} else {
|
} else {
|
||||||
messages = messages.concat(this.flattenErrors(obj[k], newKey));
|
messages = messages.concat(this.flattenErrors(obj[k], newKey));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ class RESTManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeRequest(method, url, auth, data, file) {
|
makeRequest(method, url, auth, data, file, reason) {
|
||||||
const apiRequest = new APIRequest(this, method, url, auth, data, file);
|
const apiRequest = new APIRequest(this, method, url, auth, data, file, reason);
|
||||||
if (!this.handlers[apiRequest.route]) {
|
if (!this.handlers[apiRequest.route]) {
|
||||||
const RequestHandlerType = this.getRequestHandler();
|
const RequestHandlerType = this.getRequestHandler();
|
||||||
this.handlers[apiRequest.route] = new RequestHandlerType(this, apiRequest.route);
|
this.handlers[apiRequest.route] = new RequestHandlerType(this, apiRequest.route);
|
||||||
|
|||||||
@@ -102,12 +102,12 @@ class RESTMethods {
|
|||||||
if (content instanceof Array) {
|
if (content instanceof Array) {
|
||||||
const messages = [];
|
const messages = [];
|
||||||
(function sendChunk(list, index) {
|
(function sendChunk(list, index) {
|
||||||
const options = index === list.length ? { tts, embed } : { tts };
|
const options = index === list.length - 1 ? { tts, embed, files } : { tts };
|
||||||
chan.send(list[index], options, index === list.length ? files : null).then(message => {
|
chan.send(list[index], options).then(message => {
|
||||||
messages.push(message);
|
messages.push(message);
|
||||||
if (index >= list.length - 1) return resolve(messages);
|
if (index >= list.length - 1) return resolve(messages);
|
||||||
return sendChunk(list, ++index);
|
return sendChunk(list, ++index);
|
||||||
});
|
}).catch(reject);
|
||||||
}(content, 0));
|
}(content, 0));
|
||||||
} else {
|
} else {
|
||||||
this.rest.makeRequest('post', Endpoints.Channel(chan).messages, true, {
|
this.rest.makeRequest('post', Endpoints.Channel(chan).messages, true, {
|
||||||
@@ -227,6 +227,7 @@ class RESTMethods {
|
|||||||
embed_type: options.embedType,
|
embed_type: options.embedType,
|
||||||
attachment_filename: options.attachmentFilename,
|
attachment_filename: options.attachmentFilename,
|
||||||
attachment_extension: options.attachmentExtension,
|
attachment_extension: options.attachmentExtension,
|
||||||
|
include_nsfw: options.nsfw,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const key in options) if (options[key] === undefined) delete options[key];
|
for (const key in options) if (options[key] === undefined) delete options[key];
|
||||||
@@ -251,13 +252,13 @@ class RESTMethods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createChannel(guild, channelName, channelType, overwrites) {
|
createChannel(guild, channelName, channelType, overwrites, reason) {
|
||||||
if (overwrites instanceof Collection) overwrites = overwrites.array();
|
if (overwrites instanceof Collection) overwrites = overwrites.array();
|
||||||
return this.rest.makeRequest('post', Endpoints.Guild(guild).channels, true, {
|
return this.rest.makeRequest('post', Endpoints.Guild(guild).channels, true, {
|
||||||
name: channelName,
|
name: channelName,
|
||||||
type: channelType,
|
type: channelType,
|
||||||
permission_overwrites: overwrites,
|
permission_overwrites: overwrites,
|
||||||
}).then(data => this.client.actions.ChannelCreate.handle(data).channel);
|
}, undefined, reason).then(data => this.client.actions.ChannelCreate.handle(data).channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
createDM(recipient) {
|
createDM(recipient) {
|
||||||
@@ -284,29 +285,42 @@ class RESTMethods {
|
|||||||
.then(() => channel);
|
.then(() => channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeUserFromGroupDM(channel, userId) {
|
||||||
|
return this.rest.makeRequest('delete', Endpoints.Channel(channel).Recipient(userId), true)
|
||||||
|
.then(() => channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGroupDMChannel(channel, _data) {
|
||||||
|
const data = {};
|
||||||
|
data.name = _data.name;
|
||||||
|
data.icon = _data.icon;
|
||||||
|
return this.rest.makeRequest('patch', Endpoints.Channel(channel), true, data).then(() => channel);
|
||||||
|
}
|
||||||
|
|
||||||
getExistingDM(recipient) {
|
getExistingDM(recipient) {
|
||||||
return this.client.channels.find(channel =>
|
return this.client.channels.find(channel =>
|
||||||
channel.recipient && channel.recipient.id === recipient.id
|
channel.recipient && channel.recipient.id === recipient.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteChannel(channel) {
|
deleteChannel(channel, reason) {
|
||||||
if (channel instanceof User || channel instanceof GuildMember) channel = this.getExistingDM(channel);
|
if (channel instanceof User || channel instanceof GuildMember) channel = this.getExistingDM(channel);
|
||||||
if (!channel) return Promise.reject(new Error('No channel to delete.'));
|
if (!channel) return Promise.reject(new Error('No channel to delete.'));
|
||||||
return this.rest.makeRequest('delete', Endpoints.Channel(channel), true).then(data => {
|
return this.rest.makeRequest('delete', Endpoints.Channel(channel), true, undefined, undefined, reason)
|
||||||
data.id = channel.id;
|
.then(data => {
|
||||||
return this.client.actions.ChannelDelete.handle(data).channel;
|
data.id = channel.id;
|
||||||
});
|
return this.client.actions.ChannelDelete.handle(data).channel;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateChannel(channel, _data) {
|
updateChannel(channel, _data, reason) {
|
||||||
const data = {};
|
const data = {};
|
||||||
data.name = (_data.name || channel.name).trim();
|
data.name = (_data.name || channel.name).trim();
|
||||||
data.topic = _data.topic || channel.topic;
|
data.topic = _data.topic || channel.topic;
|
||||||
data.position = _data.position || channel.position;
|
data.position = _data.position || channel.position;
|
||||||
data.bitrate = _data.bitrate || channel.bitrate;
|
data.bitrate = _data.bitrate || channel.bitrate;
|
||||||
data.user_limit = _data.userLimit || channel.userLimit;
|
data.user_limit = _data.userLimit || channel.userLimit;
|
||||||
return this.rest.makeRequest('patch', Endpoints.Channel(channel), true, data).then(newData =>
|
return this.rest.makeRequest('patch', Endpoints.Channel(channel), true, data, undefined, reason).then(newData =>
|
||||||
this.client.actions.ChannelUpdate.handle(newData).updated
|
this.client.actions.ChannelUpdate.handle(newData).updated
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -361,7 +375,7 @@ class RESTMethods {
|
|||||||
const user = this.client.user;
|
const user = this.client.user;
|
||||||
const data = {};
|
const data = {};
|
||||||
data.username = _data.username || user.username;
|
data.username = _data.username || user.username;
|
||||||
data.avatar = this.client.resolver.resolveBase64(_data.avatar) || user.avatar;
|
data.avatar = typeof _data.avatar === 'undefined' ? user.avatar : this.client.resolver.resolveBase64(_data.avatar);
|
||||||
if (!user.bot) {
|
if (!user.bot) {
|
||||||
data.email = _data.email || user.email;
|
data.email = _data.email || user.email;
|
||||||
data.password = password;
|
data.password = password;
|
||||||
@@ -372,58 +386,57 @@ class RESTMethods {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGuild(guild, _data) {
|
updateGuild(guild, data, reason) {
|
||||||
const data = {};
|
return this.rest.makeRequest('patch', Endpoints.Guild(guild), true, data, undefined, reason).then(newData =>
|
||||||
if (_data.name) data.name = _data.name;
|
|
||||||
if (_data.region) data.region = _data.region;
|
|
||||||
if (_data.verificationLevel) data.verification_level = Number(_data.verificationLevel);
|
|
||||||
if (_data.afkChannel) data.afk_channel_id = this.client.resolver.resolveChannel(_data.afkChannel).id;
|
|
||||||
if (_data.afkTimeout) data.afk_timeout = Number(_data.afkTimeout);
|
|
||||||
if (_data.icon) data.icon = this.client.resolver.resolveBase64(_data.icon);
|
|
||||||
if (_data.owner) data.owner_id = this.client.resolver.resolveUser(_data.owner).id;
|
|
||||||
if (_data.splash) data.splash = this.client.resolver.resolveBase64(_data.splash);
|
|
||||||
return this.rest.makeRequest('patch', Endpoints.Guild(guild), true, data).then(newData =>
|
|
||||||
this.client.actions.GuildUpdate.handle(newData).updated
|
this.client.actions.GuildUpdate.handle(newData).updated
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
kickGuildMember(guild, member, reason) {
|
kickGuildMember(guild, member, reason) {
|
||||||
const url = `${Endpoints.Guild(guild).Member(member)}?reason=${reason}`;
|
return this.rest.makeRequest(
|
||||||
return this.rest.makeRequest('delete', url, true).then(() =>
|
'delete', Endpoints.Guild(guild).Member(member), true,
|
||||||
this.client.actions.GuildMemberRemove.handle({
|
undefined, undefined, reason)
|
||||||
guild_id: guild.id,
|
.then(() =>
|
||||||
user: member.user,
|
this.client.actions.GuildMemberRemove.handle({
|
||||||
}).member
|
guild_id: guild.id,
|
||||||
);
|
user: member.user,
|
||||||
|
}).member
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
createGuildRole(guild, data) {
|
createGuildRole(guild, data, reason) {
|
||||||
if (data.color) data.color = this.client.resolver.resolveColor(data.color);
|
if (data.color) data.color = this.client.resolver.resolveColor(data.color);
|
||||||
if (data.permissions) data.permissions = Permissions.resolve(data.permissions);
|
if (data.permissions) data.permissions = Permissions.resolve(data.permissions);
|
||||||
return this.rest.makeRequest('post', Endpoints.Guild(guild).roles, true, data).then(role =>
|
return this.rest.makeRequest('post', Endpoints.Guild(guild).roles, true, data, undefined, reason).then(r => {
|
||||||
this.client.actions.GuildRoleCreate.handle({
|
const { role } = this.client.actions.GuildRoleCreate.handle({
|
||||||
guild_id: guild.id,
|
guild_id: guild.id,
|
||||||
role,
|
role: r,
|
||||||
}).role
|
});
|
||||||
);
|
if (data.position) return role.setPosition(data.position, reason);
|
||||||
|
return role;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteGuildRole(role) {
|
deleteGuildRole(role, reason) {
|
||||||
return this.rest.makeRequest('delete', Endpoints.Guild(role.guild).Role(role.id), true).then(() =>
|
return this.rest.makeRequest(
|
||||||
this.client.actions.GuildRoleDelete.handle({
|
'delete', Endpoints.Guild(role.guild).Role(role.id), true,
|
||||||
guild_id: role.guild.id,
|
undefined, undefined, reason)
|
||||||
role_id: role.id,
|
.then(() =>
|
||||||
}).role
|
this.client.actions.GuildRoleDelete.handle({
|
||||||
);
|
guild_id: role.guild.id,
|
||||||
|
role_id: role.id,
|
||||||
|
}).role
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setChannelOverwrite(channel, payload) {
|
setChannelOverwrite(channel, payload) {
|
||||||
return this.rest.makeRequest('put', `${Endpoints.Channel(channel).permissions}/${payload.id}`, true, payload);
|
return this.rest.makeRequest('put', `${Endpoints.Channel(channel).permissions}/${payload.id}`, true, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePermissionOverwrites(overwrite) {
|
deletePermissionOverwrites(overwrite, reason) {
|
||||||
return this.rest.makeRequest(
|
return this.rest.makeRequest(
|
||||||
'delete', `${Endpoints.Channel(overwrite.channel).permissions}/${overwrite.id}`, true
|
'delete', `${Endpoints.Channel(overwrite.channel).permissions}/${overwrite.id}`,
|
||||||
|
true, undefined, undefined, reason
|
||||||
).then(() => overwrite);
|
).then(() => overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,8 +477,11 @@ class RESTMethods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGuildMember(member, data) {
|
updateGuildMember(member, data, reason) {
|
||||||
if (data.channel) data.channel_id = this.client.resolver.resolveChannel(data.channel).id;
|
if (data.channel) {
|
||||||
|
data.channel_id = this.client.resolver.resolveChannel(data.channel).id;
|
||||||
|
data.channel = null;
|
||||||
|
}
|
||||||
if (data.roles) data.roles = data.roles.map(role => role instanceof Role ? role.id : role);
|
if (data.roles) data.roles = data.roles.map(role => role instanceof Role ? role.id : role);
|
||||||
|
|
||||||
let endpoint = Endpoints.Member(member);
|
let endpoint = Endpoints.Member(member);
|
||||||
@@ -477,12 +493,12 @@ class RESTMethods {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.rest.makeRequest('patch', endpoint, true, data).then(newData =>
|
return this.rest.makeRequest('patch', endpoint, true, data, undefined, reason).then(newData =>
|
||||||
member.guild._updateMember(member, newData).mem
|
member.guild._updateMember(member, newData).mem
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addMemberRole(member, role) {
|
addMemberRole(member, role, reason) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (member._roles.includes(role.id)) return resolve(member);
|
if (member._roles.includes(role.id)) return resolve(member);
|
||||||
|
|
||||||
@@ -497,15 +513,16 @@ class RESTMethods {
|
|||||||
const timeout = this.client.setTimeout(() =>
|
const timeout = this.client.setTimeout(() =>
|
||||||
this.client.removeListener(Constants.Events.GUILD_MEMBER_UPDATE, listener), 10e3);
|
this.client.removeListener(Constants.Events.GUILD_MEMBER_UPDATE, listener), 10e3);
|
||||||
|
|
||||||
return this.rest.makeRequest('put', Endpoints.Member(member).Role(role.id), true).catch(err => {
|
return this.rest.makeRequest('put', Endpoints.Member(member).Role(role.id), true, undefined, undefined, reason)
|
||||||
this.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
.catch(err => {
|
||||||
this.client.clearTimeout(timeout);
|
this.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
||||||
reject(err);
|
this.client.clearTimeout(timeout);
|
||||||
});
|
reject(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeMemberRole(member, role) {
|
removeMemberRole(member, role, reason) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!member._roles.includes(role.id)) return resolve(member);
|
if (!member._roles.includes(role.id)) return resolve(member);
|
||||||
|
|
||||||
@@ -520,11 +537,12 @@ class RESTMethods {
|
|||||||
const timeout = this.client.setTimeout(() =>
|
const timeout = this.client.setTimeout(() =>
|
||||||
this.client.removeListener(Constants.Events.GUILD_MEMBER_UPDATE, listener), 10e3);
|
this.client.removeListener(Constants.Events.GUILD_MEMBER_UPDATE, listener), 10e3);
|
||||||
|
|
||||||
return this.rest.makeRequest('delete', Endpoints.Member(member).Role(role.id), true).catch(err => {
|
return this.rest.makeRequest('delete', Endpoints.Member(member).Role(role.id), true, undefined, undefined, reason)
|
||||||
this.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
.catch(err => {
|
||||||
this.client.clearTimeout(timeout);
|
this.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
||||||
reject(err);
|
this.client.clearTimeout(timeout);
|
||||||
});
|
reject(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,7 +566,7 @@ class RESTMethods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
unbanGuildMember(guild, member) {
|
unbanGuildMember(guild, member, reason) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const id = this.client.resolver.resolveUserID(member);
|
const id = this.client.resolver.resolveUserID(member);
|
||||||
if (!id) throw new Error('Couldn\'t resolve the user ID to unban.');
|
if (!id) throw new Error('Couldn\'t resolve the user ID to unban.');
|
||||||
@@ -567,11 +585,12 @@ class RESTMethods {
|
|||||||
reject(new Error('Took too long to receive the ban remove event.'));
|
reject(new Error('Took too long to receive the ban remove event.'));
|
||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
this.rest.makeRequest('delete', `${Endpoints.Guild(guild).bans}/${id}`, true).catch(err => {
|
this.rest.makeRequest('delete', `${Endpoints.Guild(guild).bans}/${id}`, true, undefined, undefined, reason)
|
||||||
this.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
.catch(err => {
|
||||||
this.client.clearTimeout(timeout);
|
this.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
||||||
reject(err);
|
this.client.clearTimeout(timeout);
|
||||||
});
|
reject(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,7 +606,7 @@ class RESTMethods {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGuildRole(role, _data) {
|
updateGuildRole(role, _data, reason) {
|
||||||
const data = {};
|
const data = {};
|
||||||
data.name = _data.name || role.name;
|
data.name = _data.name || role.name;
|
||||||
data.position = typeof _data.position !== 'undefined' ? _data.position : role.position;
|
data.position = typeof _data.position !== 'undefined' ? _data.position : role.position;
|
||||||
@@ -598,12 +617,13 @@ class RESTMethods {
|
|||||||
if (_data.permissions) data.permissions = Permissions.resolve(_data.permissions);
|
if (_data.permissions) data.permissions = Permissions.resolve(_data.permissions);
|
||||||
else data.permissions = role.permissions;
|
else data.permissions = role.permissions;
|
||||||
|
|
||||||
return this.rest.makeRequest('patch', Endpoints.Guild(role.guild).Role(role.id), true, data).then(_role =>
|
return this.rest.makeRequest('patch', Endpoints.Guild(role.guild).Role(role.id), true, data, undefined, reason)
|
||||||
this.client.actions.GuildRoleUpdate.handle({
|
.then(_role =>
|
||||||
role: _role,
|
this.client.actions.GuildRoleUpdate.handle({
|
||||||
guild_id: role.guild.id,
|
role: _role,
|
||||||
}).updated
|
guild_id: role.guild.id,
|
||||||
);
|
}).updated
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pinMessage(message) {
|
pinMessage(message) {
|
||||||
@@ -620,17 +640,19 @@ class RESTMethods {
|
|||||||
return this.rest.makeRequest('get', Endpoints.Channel(channel).pins, true);
|
return this.rest.makeRequest('get', Endpoints.Channel(channel).pins, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
createChannelInvite(channel, options) {
|
createChannelInvite(channel, options, reason) {
|
||||||
const payload = {};
|
const payload = {};
|
||||||
payload.temporary = options.temporary;
|
payload.temporary = options.temporary;
|
||||||
payload.max_age = options.maxAge;
|
payload.max_age = options.maxAge;
|
||||||
payload.max_uses = options.maxUses;
|
payload.max_uses = options.maxUses;
|
||||||
return this.rest.makeRequest('post', Endpoints.Channel(channel).invites, true, payload)
|
payload.unique = options.unique;
|
||||||
|
return this.rest.makeRequest('post', Endpoints.Channel(channel).invites, true, payload, undefined, reason)
|
||||||
.then(invite => new Invite(this.client, invite));
|
.then(invite => new Invite(this.client, invite));
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteInvite(invite) {
|
deleteInvite(invite, reason) {
|
||||||
return this.rest.makeRequest('delete', Endpoints.Invite(invite.code), true).then(() => invite);
|
return this.rest.makeRequest('delete', Endpoints.Invite(invite.code), true, undefined, undefined, reason)
|
||||||
|
.then(() => invite);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInvite(code) {
|
getInvite(code) {
|
||||||
@@ -650,28 +672,31 @@ class RESTMethods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pruneGuildMembers(guild, days, dry) {
|
pruneGuildMembers(guild, days, dry, reason) {
|
||||||
return this.rest.makeRequest(dry ? 'get' : 'post', `${Endpoints.Guild(guild).prune}?days=${days}`, true)
|
return this.rest.makeRequest(dry ?
|
||||||
|
'get' :
|
||||||
|
'post',
|
||||||
|
`${Endpoints.Guild(guild).prune}?days=${days}`, true, undefined, undefined, reason)
|
||||||
.then(data => data.pruned);
|
.then(data => data.pruned);
|
||||||
}
|
}
|
||||||
|
|
||||||
createEmoji(guild, image, name, roles) {
|
createEmoji(guild, image, name, roles, reason) {
|
||||||
const data = { image, name };
|
const data = { image, name };
|
||||||
if (roles) data.roles = roles.map(r => r.id ? r.id : r);
|
if (roles) data.roles = roles.map(r => r.id ? r.id : r);
|
||||||
return this.rest.makeRequest('post', Endpoints.Guild(guild).emojis, true, data)
|
return this.rest.makeRequest('post', Endpoints.Guild(guild).emojis, true, data, undefined, reason)
|
||||||
.then(emoji => this.client.actions.GuildEmojiCreate.handle(guild, emoji).emoji);
|
.then(emoji => this.client.actions.GuildEmojiCreate.handle(guild, emoji).emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEmoji(emoji, _data) {
|
updateEmoji(emoji, _data, reason) {
|
||||||
const data = {};
|
const data = {};
|
||||||
if (_data.name) data.name = _data.name;
|
if (_data.name) data.name = _data.name;
|
||||||
if (_data.roles) data.roles = _data.roles.map(r => r.id ? r.id : r);
|
if (_data.roles) data.roles = _data.roles.map(r => r.id ? r.id : r);
|
||||||
return this.rest.makeRequest('patch', Endpoints.Guild(emoji.guild).Emoji(emoji.id), true, data)
|
return this.rest.makeRequest('patch', Endpoints.Guild(emoji.guild).Emoji(emoji.id), true, data, undefined, reason)
|
||||||
.then(newEmoji => this.client.actions.GuildEmojiUpdate.handle(emoji, newEmoji).emoji);
|
.then(newEmoji => this.client.actions.GuildEmojiUpdate.handle(emoji, newEmoji).emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteEmoji(emoji) {
|
deleteEmoji(emoji, reason) {
|
||||||
return this.rest.makeRequest('delete', Endpoints.Guild(emoji.guild).Emoji(emoji.id), true)
|
return this.rest.makeRequest('delete', Endpoints.Guild(emoji.guild).Emoji(emoji.id), true, undefined, reason)
|
||||||
.then(() => this.client.actions.GuildEmojiDelete.handle(emoji).data);
|
.then(() => this.client.actions.GuildEmojiDelete.handle(emoji).data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,8 +739,8 @@ class RESTMethods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createWebhook(channel, name, avatar) {
|
createWebhook(channel, name, avatar, reason) {
|
||||||
return this.rest.makeRequest('post', Endpoints.Channel(channel).webhooks, true, { name, avatar })
|
return this.rest.makeRequest('post', Endpoints.Channel(channel).webhooks, true, { name, avatar }, undefined, reason)
|
||||||
.then(data => new Webhook(this.client, data));
|
.then(data => new Webhook(this.client, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,25 +755,36 @@ class RESTMethods {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteWebhook(webhook) {
|
deleteWebhook(webhook, reason) {
|
||||||
return this.rest.makeRequest('delete', Endpoints.Webhook(webhook.id, webhook.token), false);
|
return this.rest.makeRequest(
|
||||||
|
'delete', Endpoints.Webhook(webhook.id, webhook.token),
|
||||||
|
false, undefined, undefined, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendWebhookMessage(webhook, content, { avatarURL, tts, disableEveryone, embeds, username } = {}, file = null) {
|
sendWebhookMessage(webhook, content, { avatarURL, tts, embeds, username } = {}, files = null) {
|
||||||
username = username || webhook.name;
|
return new Promise((resolve, reject) => {
|
||||||
if (typeof content !== 'undefined') content = this.client.resolver.resolveString(content);
|
username = username || webhook.name;
|
||||||
if (content) {
|
|
||||||
if (disableEveryone || (typeof disableEveryone === 'undefined' && this.client.options.disableEveryone)) {
|
if (content instanceof Array) {
|
||||||
content = content.replace(/@(everyone|here)/g, '@\u200b$1');
|
const messages = [];
|
||||||
|
(function sendChunk(list, index) {
|
||||||
|
const options = index === list.length - 1 ? { tts, embeds, files } : { tts };
|
||||||
|
webhook.send(list[index], options).then(message => {
|
||||||
|
messages.push(message);
|
||||||
|
if (index >= list.length - 1) return resolve(messages);
|
||||||
|
return sendChunk(list, ++index);
|
||||||
|
}).catch(reject);
|
||||||
|
}(content, 0));
|
||||||
|
} else {
|
||||||
|
this.rest.makeRequest('post', `${Endpoints.Webhook(webhook.id, webhook.token)}?wait=true`, false, {
|
||||||
|
username,
|
||||||
|
avatar_url: avatarURL,
|
||||||
|
content,
|
||||||
|
tts,
|
||||||
|
embeds,
|
||||||
|
}, files).then(resolve, reject);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return this.rest.makeRequest('post', `${Endpoints.Webhook(webhook.id, webhook.token)}?wait=true`, false, {
|
|
||||||
username,
|
|
||||||
avatar_url: avatarURL,
|
|
||||||
content,
|
|
||||||
tts,
|
|
||||||
embeds,
|
|
||||||
}, file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSlackWebhookMessage(webhook, body) {
|
sendSlackWebhookMessage(webhook, body) {
|
||||||
@@ -763,12 +799,13 @@ class RESTMethods {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchMeMentions(options) {
|
fetchMentions(options) {
|
||||||
if (options.guild) options.guild = options.guild.id ? options.guild.id : options.guild;
|
if (options.guild instanceof Guild) options.guild = options.guild.id;
|
||||||
|
Util.mergeDefault({ limit: 25, roles: true, everyone: true, guild: null }, options);
|
||||||
|
|
||||||
return this.rest.makeRequest(
|
return this.rest.makeRequest(
|
||||||
'get',
|
'get', Endpoints.User('@me').Mentions(options.limit, options.roles, options.everyone, options.guild), true
|
||||||
Endpoints.User('@me').mentions(options.limit, options.roles, options.everyone, options.guild)
|
).then(data => data.map(m => new Message(this.client.channels.get(m.channel_id), m, this.client)));
|
||||||
).then(res => res.body.map(m => new Message(this.client.channels.get(m.channel_id), m, this.client)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addFriend(user) {
|
addFriend(user) {
|
||||||
@@ -833,7 +870,7 @@ class RESTMethods {
|
|||||||
'put', Endpoints.Message(message).Reaction(emoji).User('@me'), true
|
'put', Endpoints.Message(message).Reaction(emoji).User('@me'), true
|
||||||
).then(() =>
|
).then(() =>
|
||||||
message._addReaction(Util.parseEmoji(emoji), message.client.user)
|
message._addReaction(Util.parseEmoji(emoji), message.client.user)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeMessageReaction(message, emoji, userID) {
|
removeMessageReaction(message, emoji, userID) {
|
||||||
@@ -864,7 +901,8 @@ class RESTMethods {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetApplication(id) {
|
resetApplication(id) {
|
||||||
return this.rest.makeRequest('post', Endpoints.OAUTH2.Application(id).reset, true)
|
return this.rest.makeRequest('post', Endpoints.OAUTH2.Application(id).resetToken, true)
|
||||||
|
.then(() => this.rest.makeRequest('post', Endpoints.OAUTH2.Application(id).resetSecret, true))
|
||||||
.then(app => new OAuth2Application(this.client, app));
|
.then(app => new OAuth2Application(this.client, app));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -894,6 +932,10 @@ class RESTMethods {
|
|||||||
patchUserSettings(data) {
|
patchUserSettings(data) {
|
||||||
return this.rest.makeRequest('patch', Constants.Endpoints.User('@me').settings, true, data);
|
return this.rest.makeRequest('patch', Constants.Endpoints.User('@me').settings, true, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
patchClientUserGuildSettings(guildID, data) {
|
||||||
|
return this.rest.makeRequest('patch', Constants.Endpoints.User('@me').Guild(guildID).settings, true, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RESTMethods;
|
module.exports = RESTMethods;
|
||||||
|
|||||||
@@ -40,8 +40,14 @@ class BurstRequestHandler extends RequestHandler {
|
|||||||
this.handle();
|
this.handle();
|
||||||
this.resetTimeout = null;
|
this.resetTimeout = null;
|
||||||
}, Number(res.headers['retry-after']) + this.client.options.restTimeOffset);
|
}, Number(res.headers['retry-after']) + this.client.options.restTimeOffset);
|
||||||
|
} else if (err.status >= 500 && err.status < 600) {
|
||||||
|
this.queue.unshift(item);
|
||||||
|
this.resetTimeout = this.client.setTimeout(() => {
|
||||||
|
this.handle();
|
||||||
|
this.resetTimeout = null;
|
||||||
|
}, 1e3 + this.client.options.restTimeOffset);
|
||||||
} else {
|
} else {
|
||||||
item.reject(err.status === 400 ? new DiscordAPIError(res.body) : err);
|
item.reject(err.status >= 400 && err.status < 500 ? new DiscordAPIError(res.request.path, res.body) : err);
|
||||||
this.handle();
|
this.handle();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -64,8 +64,11 @@ class SequentialRequestHandler extends RequestHandler {
|
|||||||
resolve();
|
resolve();
|
||||||
}, Number(res.headers['retry-after']) + this.restManager.client.options.restTimeOffset);
|
}, Number(res.headers['retry-after']) + this.restManager.client.options.restTimeOffset);
|
||||||
if (res.headers['x-ratelimit-global']) this.globalLimit = true;
|
if (res.headers['x-ratelimit-global']) this.globalLimit = true;
|
||||||
|
} else if (err.status >= 500 && err.status < 600) {
|
||||||
|
this.queue.unshift(item);
|
||||||
|
this.restManager.client.setTimeout(resolve, 1e3 + this.client.options.restTimeOffset);
|
||||||
} else {
|
} else {
|
||||||
item.reject(err.status >= 400 && err.status < 500 ? new DiscordAPIError(res.body) : err);
|
item.reject(err.status >= 400 && err.status < 500 ? new DiscordAPIError(res.request.path, res.body) : err);
|
||||||
resolve(err);
|
resolve(err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const ffmpegArguments = [
|
|||||||
* ```js
|
* ```js
|
||||||
* const broadcast = client.createVoiceBroadcast();
|
* const broadcast = client.createVoiceBroadcast();
|
||||||
* broadcast.playFile('./music.mp3');
|
* broadcast.playFile('./music.mp3');
|
||||||
* // play "music.mp3" in all voice connections that the client is in
|
* // Play "music.mp3" in all voice connections that the client is in
|
||||||
* for (const connection of client.voiceConnections.values()) {
|
* for (const connection of client.voiceConnections.values()) {
|
||||||
* connection.playBroadcast(broadcast);
|
* connection.playBroadcast(broadcast);
|
||||||
* }
|
* }
|
||||||
@@ -136,15 +136,15 @@ class VoiceBroadcast extends VolumeInterface {
|
|||||||
* const broadcast = client.createVoiceBroadcast();
|
* const broadcast = client.createVoiceBroadcast();
|
||||||
*
|
*
|
||||||
* voiceChannel.join()
|
* voiceChannel.join()
|
||||||
* .then(connection => {
|
* .then(connection => {
|
||||||
* const stream = ytdl('https://www.youtube.com/watch?v=XAWgeLF9EVQ', { filter : 'audioonly' });
|
* const stream = ytdl('https://www.youtube.com/watch?v=XAWgeLF9EVQ', { filter : 'audioonly' });
|
||||||
* broadcast.playStream(stream);
|
* broadcast.playStream(stream);
|
||||||
* const dispatcher = connection.playBroadcast(broadcast);
|
* const dispatcher = connection.playBroadcast(broadcast);
|
||||||
* })
|
* })
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
playStream(stream, { seek = 0, volume = 1, passes = 1 } = {}) {
|
playStream(stream, options = {}) {
|
||||||
const options = { seek, volume, passes, stream };
|
this.setVolume(options.volume || 1);
|
||||||
return this._playTranscodable(stream, options);
|
return this._playTranscodable(stream, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,25 +158,23 @@ class VoiceBroadcast extends VolumeInterface {
|
|||||||
* const broadcast = client.createVoiceBroadcast();
|
* const broadcast = client.createVoiceBroadcast();
|
||||||
*
|
*
|
||||||
* voiceChannel.join()
|
* voiceChannel.join()
|
||||||
* .then(connection => {
|
* .then(connection => {
|
||||||
* broadcast.playFile('C:/Users/Discord/Desktop/music.mp3');
|
* broadcast.playFile('C:/Users/Discord/Desktop/music.mp3');
|
||||||
* const dispatcher = connection.playBroadcast(broadcast);
|
* const dispatcher = connection.playBroadcast(broadcast);
|
||||||
* })
|
* })
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
playFile(file, { seek = 0, volume = 1, passes = 1 } = {}) {
|
playFile(file, options = {}) {
|
||||||
const options = { seek, volume, passes };
|
this.setVolume(options.volume || 1);
|
||||||
return this._playTranscodable(`file:${file}`, options);
|
return this._playTranscodable(`file:${file}`, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_playTranscodable(media, options) {
|
_playTranscodable(media, options) {
|
||||||
OpusEncoders.guaranteeOpusEngine();
|
|
||||||
|
|
||||||
this.killCurrentTranscoder();
|
this.killCurrentTranscoder();
|
||||||
const transcoder = this.prism.transcode({
|
const transcoder = this.prism.transcode({
|
||||||
type: 'ffmpeg',
|
type: 'ffmpeg',
|
||||||
media,
|
media,
|
||||||
ffmpegArguments: ffmpegArguments.concat(['-ss', String(options.seek)]),
|
ffmpegArguments: ffmpegArguments.concat(['-ss', String(options.seek || 0)]),
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
* Emitted whenever an error occurs.
|
* Emitted whenever an error occurs.
|
||||||
@@ -206,31 +204,28 @@ class VoiceBroadcast extends VolumeInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays a stream of 16-bit signed stereo PCM at 48KHz.
|
* Plays a stream of 16-bit signed stereo PCM.
|
||||||
* @param {ReadableStream} stream The audio stream to play
|
* @param {ReadableStream} stream The audio stream to play
|
||||||
* @param {StreamOptions} [options] Options for playing the stream
|
* @param {StreamOptions} [options] Options for playing the stream
|
||||||
* @returns {VoiceBroadcast}
|
* @returns {VoiceBroadcast}
|
||||||
*/
|
*/
|
||||||
playConvertedStream(stream, { seek = 0, volume = 1, passes = 1 } = {}) {
|
playConvertedStream(stream, options = {}) {
|
||||||
OpusEncoders.guaranteeOpusEngine();
|
|
||||||
|
|
||||||
this.killCurrentTranscoder();
|
this.killCurrentTranscoder();
|
||||||
const options = { seek, volume, passes, stream };
|
this.setVolume(options.volume || 1);
|
||||||
this.currentTranscoder = { options };
|
this.currentTranscoder = { options: { stream } };
|
||||||
stream.once('readable', () => this._startPlaying());
|
stream.once('readable', () => this._startPlaying());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays an Opus encoded stream at 48KHz.
|
* Plays an Opus encoded stream.
|
||||||
* <warn>Note that inline volume is not compatible with this method.</warn>
|
* <warn>Note that inline volume is not compatible with this method.</warn>
|
||||||
* @param {ReadableStream} stream The Opus audio stream to play
|
* @param {ReadableStream} stream The Opus audio stream to play
|
||||||
* @param {StreamOptions} [options] Options for playing the stream
|
* @param {StreamOptions} [options] Options for playing the stream
|
||||||
* @returns {StreamDispatcher}
|
* @returns {StreamDispatcher}
|
||||||
*/
|
*/
|
||||||
playOpusStream(stream, { seek = 0, passes = 1 } = {}) {
|
playOpusStream(stream) {
|
||||||
const options = { seek, passes, stream };
|
this.currentTranscoder = { options: { stream }, opus: true };
|
||||||
this.currentTranscoder = { options, opus: true };
|
|
||||||
stream.once('readable', () => this._startPlaying());
|
stream.once('readable', () => this._startPlaying());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -241,10 +236,9 @@ class VoiceBroadcast extends VolumeInterface {
|
|||||||
* @param {StreamOptions} [options] Options for playing the stream
|
* @param {StreamOptions} [options] Options for playing the stream
|
||||||
* @returns {VoiceBroadcast}
|
* @returns {VoiceBroadcast}
|
||||||
*/
|
*/
|
||||||
playArbitraryInput(input, { seek = 0, volume = 1, passes = 1 } = {}) {
|
playArbitraryInput(input, options = {}) {
|
||||||
this.guaranteeOpusEngine();
|
this.setVolume(options.volume || 1);
|
||||||
|
options.input = input;
|
||||||
const options = { seek, volume, passes, input };
|
|
||||||
return this._playTranscodable(input, options);
|
return this._playTranscodable(input, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,10 +266,6 @@ class VoiceBroadcast extends VolumeInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guaranteeOpusEngine() {
|
|
||||||
if (!this.opusEncoder) throw new Error('Couldn\'t find an Opus engine.');
|
|
||||||
}
|
|
||||||
|
|
||||||
_startPlaying() {
|
_startPlaying() {
|
||||||
if (this.tickInterval) clearInterval(this.tickInterval);
|
if (this.tickInterval) clearInterval(this.tickInterval);
|
||||||
// Old code?
|
// Old code?
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ const EventEmitter = require('events').EventEmitter;
|
|||||||
const Prism = require('prism-media');
|
const Prism = require('prism-media');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a connection to a voice channel in Discord.
|
* Represents a connection to a guild's voice server.
|
||||||
* ```js
|
* ```js
|
||||||
* // Obtained using:
|
* // Obtained using:
|
||||||
* voiceChannel.join().then(connection => {
|
* voiceChannel.join()
|
||||||
|
* .then(connection => {
|
||||||
*
|
*
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
* @extends {EventEmitter}
|
* @extends {EventEmitter}
|
||||||
*/
|
*/
|
||||||
@@ -132,6 +133,7 @@ class VoiceConnection extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
setSpeaking(value) {
|
setSpeaking(value) {
|
||||||
if (this.speaking === value) return;
|
if (this.speaking === value) return;
|
||||||
|
if (this.status !== Constants.VoiceStatus.CONNECTED) return;
|
||||||
this.speaking = value;
|
this.speaking = value;
|
||||||
this.sockets.ws.sendPacket({
|
this.sockets.ws.sendPacket({
|
||||||
op: Constants.VoiceOPCodes.SPEAKING,
|
op: Constants.VoiceOPCodes.SPEAKING,
|
||||||
@@ -163,7 +165,7 @@ class VoiceConnection extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the token and endpoint required to connect to the the voice servers.
|
* Set the token and endpoint required to connect to the voice servers.
|
||||||
* @param {string} token The voice token
|
* @param {string} token The voice token
|
||||||
* @param {string} endpoint The voice endpoint
|
* @param {string} endpoint The voice endpoint
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
@@ -245,7 +247,6 @@ class VoiceConnection extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
authenticateFailed(reason) {
|
authenticateFailed(reason) {
|
||||||
clearTimeout(this.connectTimeout);
|
clearTimeout(this.connectTimeout);
|
||||||
this.status = Constants.VoiceStatus.DISCONNECTED;
|
|
||||||
if (this.status === Constants.VoiceStatus.AUTHENTICATING) {
|
if (this.status === Constants.VoiceStatus.AUTHENTICATING) {
|
||||||
/**
|
/**
|
||||||
* Emitted when we fail to initiate a voice connection.
|
* Emitted when we fail to initiate a voice connection.
|
||||||
@@ -256,6 +257,7 @@ class VoiceConnection extends EventEmitter {
|
|||||||
} else {
|
} else {
|
||||||
this.emit('error', new Error(reason));
|
this.emit('error', new Error(reason));
|
||||||
}
|
}
|
||||||
|
this.status = Constants.VoiceStatus.DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -430,6 +432,8 @@ class VoiceConnection extends EventEmitter {
|
|||||||
* @property {number} [seek=0] The time to seek to
|
* @property {number} [seek=0] The time to seek to
|
||||||
* @property {number} [volume=1] The volume to play at
|
* @property {number} [volume=1] The volume to play at
|
||||||
* @property {number} [passes=1] How many times to send the voice packet to reduce packet loss
|
* @property {number} [passes=1] How many times to send the voice packet to reduce packet loss
|
||||||
|
* @property {number|string} [bitrate=48000] The bitrate (quality) of the audio.
|
||||||
|
* If set to 'auto', the voice channel's bitrate will be used
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -440,10 +444,10 @@ class VoiceConnection extends EventEmitter {
|
|||||||
* @example
|
* @example
|
||||||
* // Play files natively
|
* // Play files natively
|
||||||
* voiceChannel.join()
|
* voiceChannel.join()
|
||||||
* .then(connection => {
|
* .then(connection => {
|
||||||
* const dispatcher = connection.playFile('C:/Users/Discord/Desktop/music.mp3');
|
* const dispatcher = connection.playFile('C:/Users/Discord/Desktop/music.mp3');
|
||||||
* })
|
* })
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
playFile(file, options) {
|
playFile(file, options) {
|
||||||
return this.player.playUnknownStream(`file:${file}`, options);
|
return this.player.playUnknownStream(`file:${file}`, options);
|
||||||
@@ -469,18 +473,18 @@ class VoiceConnection extends EventEmitter {
|
|||||||
* const ytdl = require('ytdl-core');
|
* const ytdl = require('ytdl-core');
|
||||||
* const streamOptions = { seek: 0, volume: 1 };
|
* const streamOptions = { seek: 0, volume: 1 };
|
||||||
* voiceChannel.join()
|
* voiceChannel.join()
|
||||||
* .then(connection => {
|
* .then(connection => {
|
||||||
* const stream = ytdl('https://www.youtube.com/watch?v=XAWgeLF9EVQ', { filter : 'audioonly' });
|
* const stream = ytdl('https://www.youtube.com/watch?v=XAWgeLF9EVQ', { filter : 'audioonly' });
|
||||||
* const dispatcher = connection.playStream(stream, streamOptions);
|
* const dispatcher = connection.playStream(stream, streamOptions);
|
||||||
* })
|
* })
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
playStream(stream, options) {
|
playStream(stream, options) {
|
||||||
return this.player.playUnknownStream(stream, options);
|
return this.player.playUnknownStream(stream, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays a stream of 16-bit signed stereo PCM at 48KHz.
|
* Plays a stream of 16-bit signed stereo PCM.
|
||||||
* @param {ReadableStream} stream The audio stream to play
|
* @param {ReadableStream} stream The audio stream to play
|
||||||
* @param {StreamOptions} [options] Options for playing the stream
|
* @param {StreamOptions} [options] Options for playing the stream
|
||||||
* @returns {StreamDispatcher}
|
* @returns {StreamDispatcher}
|
||||||
@@ -490,7 +494,7 @@ class VoiceConnection extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays an Opus encoded stream at 48KHz.
|
* Plays an Opus encoded stream.
|
||||||
* <warn>Note that inline volume is not compatible with this method.</warn>
|
* <warn>Note that inline volume is not compatible with this method.</warn>
|
||||||
* @param {ReadableStream} stream The Opus audio stream to play
|
* @param {ReadableStream} stream The Opus audio stream to play
|
||||||
* @param {StreamOptions} [options] Options for playing the stream
|
* @param {StreamOptions} [options] Options for playing the stream
|
||||||
@@ -503,6 +507,7 @@ class VoiceConnection extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Plays a voice broadcast.
|
* Plays a voice broadcast.
|
||||||
* @param {VoiceBroadcast} broadcast The broadcast to play
|
* @param {VoiceBroadcast} broadcast The broadcast to play
|
||||||
|
* @param {StreamOptions} [options] Options for playing the stream
|
||||||
* @returns {StreamDispatcher}
|
* @returns {StreamDispatcher}
|
||||||
* @example
|
* @example
|
||||||
* // Play a broadcast
|
* // Play a broadcast
|
||||||
@@ -511,12 +516,13 @@ class VoiceConnection extends EventEmitter {
|
|||||||
* .playFile('./test.mp3');
|
* .playFile('./test.mp3');
|
||||||
* const dispatcher = voiceConnection.playBroadcast(broadcast);
|
* const dispatcher = voiceConnection.playBroadcast(broadcast);
|
||||||
*/
|
*/
|
||||||
playBroadcast(broadcast) {
|
playBroadcast(broadcast, options) {
|
||||||
return this.player.playBroadcast(broadcast);
|
return this.player.playBroadcast(broadcast, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a VoiceReceiver so you can start listening to voice data. It's recommended to only create one of these.
|
* Creates a VoiceReceiver so you can start listening to voice data.
|
||||||
|
* It's recommended to only create one of these.
|
||||||
* @returns {VoiceReceiver}
|
* @returns {VoiceReceiver}
|
||||||
*/
|
*/
|
||||||
createReceiver() {
|
createReceiver() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const VolumeInterface = require('../util/VolumeInterface');
|
const VolumeInterface = require('../util/VolumeInterface');
|
||||||
const VoiceBroadcast = require('../VoiceBroadcast');
|
const VoiceBroadcast = require('../VoiceBroadcast');
|
||||||
|
const Constants = require('../../../util/Constants');
|
||||||
|
|
||||||
const secretbox = require('../util/Secretbox');
|
const secretbox = require('../util/Secretbox');
|
||||||
|
|
||||||
@@ -88,12 +89,12 @@ class StreamDispatcher extends VolumeInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops sending voice packets to the voice connection (stream may still progress however)
|
* Stops sending voice packets to the voice connection (stream may still progress however).
|
||||||
*/
|
*/
|
||||||
pause() { this.setPaused(true); }
|
pause() { this.setPaused(true); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resumes sending voice packets to the voice connection (may be further on in the stream than when paused)
|
* Resumes sending voice packets to the voice connection (may be further on in the stream than when paused).
|
||||||
*/
|
*/
|
||||||
resume() { this.setPaused(false); }
|
resume() { this.setPaused(false); }
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@ class StreamDispatcher extends VolumeInterface {
|
|||||||
|
|
||||||
setSpeaking(value) {
|
setSpeaking(value) {
|
||||||
if (this.speaking === value) return;
|
if (this.speaking === value) return;
|
||||||
|
if (this.player.voiceConnection.status !== Constants.VoiceStatus.CONNECTED) return;
|
||||||
this.speaking = value;
|
this.speaking = value;
|
||||||
/**
|
/**
|
||||||
* Emitted when the dispatcher starts/stops speaking.
|
* Emitted when the dispatcher starts/stops speaking.
|
||||||
@@ -117,6 +119,16 @@ class StreamDispatcher extends VolumeInterface {
|
|||||||
this.emit('speaking', value);
|
this.emit('speaking', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the bitrate of the current Opus encoder.
|
||||||
|
* @param {number} bitrate New bitrate, in kbps
|
||||||
|
* If set to 'auto', the voice channel's bitrate will be used
|
||||||
|
*/
|
||||||
|
setBitrate(bitrate) {
|
||||||
|
this.player.setBitrate(bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
sendBuffer(buffer, sequence, timestamp, opusPacket) {
|
sendBuffer(buffer, sequence, timestamp, opusPacket) {
|
||||||
opusPacket = opusPacket || this.player.opusEncoder.encode(buffer);
|
opusPacket = opusPacket || this.player.opusEncoder.encode(buffer);
|
||||||
const packet = this.createPacket(sequence, timestamp, opusPacket);
|
const packet = this.createPacket(sequence, timestamp, opusPacket);
|
||||||
@@ -128,7 +140,7 @@ class StreamDispatcher extends VolumeInterface {
|
|||||||
/**
|
/**
|
||||||
* Emitted whenever the dispatcher has debug information.
|
* Emitted whenever the dispatcher has debug information.
|
||||||
* @event StreamDispatcher#debug
|
* @event StreamDispatcher#debug
|
||||||
* @param {string} info the debug info
|
* @param {string} info The debug info
|
||||||
*/
|
*/
|
||||||
this.setSpeaking(true);
|
this.setSpeaking(true);
|
||||||
while (repeats--) {
|
while (repeats--) {
|
||||||
@@ -282,7 +294,7 @@ class StreamDispatcher extends VolumeInterface {
|
|||||||
this.emit(type, reason);
|
this.emit(type, reason);
|
||||||
/**
|
/**
|
||||||
* Emitted once the dispatcher ends.
|
* Emitted once the dispatcher ends.
|
||||||
* @param {string} [reason] the reason the dispatcher ended
|
* @param {string} [reason] The reason the dispatcher ended
|
||||||
* @event StreamDispatcher#end
|
* @event StreamDispatcher#end
|
||||||
*/
|
*/
|
||||||
if (type !== 'end') this.emit('end', `destroyed due to ${type} - ${reason}`);
|
if (type !== 'end') this.emit('end', `destroyed due to ${type} - ${reason}`);
|
||||||
|
|||||||
@@ -5,20 +5,37 @@
|
|||||||
class BaseOpus {
|
class BaseOpus {
|
||||||
/**
|
/**
|
||||||
* @param {Object} [options] The options to apply to the Opus engine
|
* @param {Object} [options] The options to apply to the Opus engine
|
||||||
* @param {boolean} [options.fec] Whether to enable forward error correction (defaults to false)
|
* @param {number} [options.bitrate=48] The desired bitrate (kbps)
|
||||||
* @param {number} [options.plp] The expected packet loss percentage (0-1 inclusive, defaults to 0)
|
* @param {boolean} [options.fec=false] Whether to enable forward error correction
|
||||||
|
* @param {number} [options.plp=0] The expected packet loss percentage
|
||||||
*/
|
*/
|
||||||
constructor(options = {}) {
|
constructor({ bitrate = 48, fec = false, plp = 0 } = {}) {
|
||||||
this.ctl = {
|
this.ctl = {
|
||||||
|
BITRATE: 4002,
|
||||||
FEC: 4012,
|
FEC: 4012,
|
||||||
PLP: 4014,
|
PLP: 4014,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.options = options;
|
this.samplingRate = 48000;
|
||||||
|
this.channels = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The desired bitrate (kbps)
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.bitrate = bitrate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Miscellaneous Opus options
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
this.options = { fec, plp };
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
try {
|
try {
|
||||||
|
this.setBitrate(this.bitrate);
|
||||||
|
|
||||||
// Set FEC (forward error correction)
|
// Set FEC (forward error correction)
|
||||||
if (this.options.fec) this.setFEC(this.options.fec);
|
if (this.options.fec) this.setFEC(this.options.fec);
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,14 @@ class NodeOpusEngine extends OpusEngine {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
this.encoder = new opus.OpusEncoder(48000, 2);
|
this.encoder = new opus.OpusEncoder(this.samplingRate, this.channels);
|
||||||
super.init();
|
super.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBitrate(bitrate) {
|
||||||
|
this.encoder.applyEncoderCTL(this.ctl.BITRATE, Math.min(128, Math.max(16, bitrate)) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
setFEC(enabled) {
|
setFEC(enabled) {
|
||||||
this.encoder.applyEncoderCTL(this.ctl.FEC, enabled ? 1 : 0);
|
this.encoder.applyEncoderCTL(this.ctl.FEC, enabled ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ const list = [
|
|||||||
require('./OpusScriptEngine'),
|
require('./OpusScriptEngine'),
|
||||||
];
|
];
|
||||||
|
|
||||||
let opusEngineFound;
|
|
||||||
|
|
||||||
function fetch(Encoder, engineOptions) {
|
function fetch(Encoder, engineOptions) {
|
||||||
try {
|
try {
|
||||||
return new Encoder(engineOptions);
|
return new Encoder(engineOptions);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return null;
|
if (err.message.includes('Cannot find module')) return null;
|
||||||
|
|
||||||
|
// The Opus engine exists, but another error occurred.
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,10 +23,6 @@ exports.fetch = engineOptions => {
|
|||||||
const fetched = fetch(encoder, engineOptions);
|
const fetched = fetch(encoder, engineOptions);
|
||||||
if (fetched) return fetched;
|
if (fetched) return fetched;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.guaranteeOpusEngine = () => {
|
throw new Error('OPUS_ENGINE_MISSING');
|
||||||
if (typeof opusEngineFound === 'undefined') opusEngineFound = Boolean(exports.fetch());
|
|
||||||
if (!opusEngineFound) throw new Error('Couldn\'t find an Opus engine.');
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,10 +10,14 @@ class OpusScriptEngine extends OpusEngine {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
this.encoder = new OpusScript(48000, 2);
|
this.encoder = new OpusScript(this.samplingRate, this.channels);
|
||||||
super.init();
|
super.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBitrate(bitrate) {
|
||||||
|
this.encoder.encoderCTL(this.ctl.BITRATE, Math.min(128, Math.max(16, bitrate)) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
setFEC(enabled) {
|
setFEC(enabled) {
|
||||||
this.encoder.encoderCTL(this.ctl.FEC, enabled ? 1 : 0);
|
this.encoder.encoderCTL(this.ctl.FEC, enabled ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,6 @@ class AudioPlayer extends EventEmitter {
|
|||||||
* @type {Prism}
|
* @type {Prism}
|
||||||
*/
|
*/
|
||||||
this.prism = new Prism();
|
this.prism = new Prism();
|
||||||
/**
|
|
||||||
* The opus encoder that the player uses
|
|
||||||
* @type {NodeOpusEngine|OpusScriptEngine}
|
|
||||||
*/
|
|
||||||
this.opusEncoder = OpusEncoders.fetch();
|
|
||||||
this.streams = new Collection();
|
this.streams = new Collection();
|
||||||
this.currentStream = {};
|
this.currentStream = {};
|
||||||
this.streamingData = {
|
this.streamingData = {
|
||||||
@@ -67,6 +62,7 @@ class AudioPlayer extends EventEmitter {
|
|||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this.opusEncoder) this.opusEncoder.destroy();
|
if (this.opusEncoder) this.opusEncoder.destroy();
|
||||||
|
this.opusEncoder = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyCurrentStream() {
|
destroyCurrentStream() {
|
||||||
@@ -83,13 +79,25 @@ class AudioPlayer extends EventEmitter {
|
|||||||
this.currentStream = {};
|
this.currentStream = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
playUnknownStream(stream, { seek = 0, volume = 1, passes = 1 } = {}) {
|
/**
|
||||||
OpusEncoders.guaranteeOpusEngine();
|
* Set the bitrate of the current Opus encoder.
|
||||||
const options = { seek, volume, passes };
|
* @param {number} value New bitrate, in kbps
|
||||||
|
* If set to 'auto', the voice channel's bitrate will be used
|
||||||
|
*/
|
||||||
|
setBitrate(value) {
|
||||||
|
if (!value) return;
|
||||||
|
if (!this.opusEncoder) return;
|
||||||
|
const bitrate = value === 'auto' ? this.voiceConnection.channel.bitrate : value;
|
||||||
|
this.opusEncoder.setBitrate(bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
playUnknownStream(stream, options = {}) {
|
||||||
|
this.destroy();
|
||||||
|
this.opusEncoder = OpusEncoders.fetch(options);
|
||||||
const transcoder = this.prism.transcode({
|
const transcoder = this.prism.transcode({
|
||||||
type: 'ffmpeg',
|
type: 'ffmpeg',
|
||||||
media: stream,
|
media: stream,
|
||||||
ffmpegArguments: ffmpegArguments.concat(['-ss', String(seek)]),
|
ffmpegArguments: ffmpegArguments.concat(['-ss', String(options.seek || 0)]),
|
||||||
});
|
});
|
||||||
this.destroyCurrentStream();
|
this.destroyCurrentStream();
|
||||||
this.currentStream = {
|
this.currentStream = {
|
||||||
@@ -105,9 +113,10 @@ class AudioPlayer extends EventEmitter {
|
|||||||
return this.playPCMStream(transcoder.output, options, true);
|
return this.playPCMStream(transcoder.output, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
playPCMStream(stream, { seek = 0, volume = 1, passes = 1 } = {}, fromUnknown = false) {
|
playPCMStream(stream, options = {}, fromUnknown = false) {
|
||||||
OpusEncoders.guaranteeOpusEngine();
|
this.destroy();
|
||||||
const options = { seek, volume, passes };
|
this.opusEncoder = OpusEncoders.fetch(options);
|
||||||
|
this.setBitrate(options.bitrate);
|
||||||
const dispatcher = this.createDispatcher(stream, options);
|
const dispatcher = this.createDispatcher(stream, options);
|
||||||
if (fromUnknown) {
|
if (fromUnknown) {
|
||||||
this.currentStream.dispatcher = dispatcher;
|
this.currentStream.dispatcher = dispatcher;
|
||||||
@@ -122,8 +131,8 @@ class AudioPlayer extends EventEmitter {
|
|||||||
return dispatcher;
|
return dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
playOpusStream(stream, { seek = 0, passes = 1 } = {}) {
|
playOpusStream(stream, options = {}) {
|
||||||
const options = { seek, passes, opus: true };
|
options.opus = true;
|
||||||
this.destroyCurrentStream();
|
this.destroyCurrentStream();
|
||||||
const dispatcher = this.createDispatcher(stream, options);
|
const dispatcher = this.createDispatcher(stream, options);
|
||||||
this.currentStream = {
|
this.currentStream = {
|
||||||
@@ -134,8 +143,7 @@ class AudioPlayer extends EventEmitter {
|
|||||||
return dispatcher;
|
return dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
playBroadcast(broadcast, { volume = 1, passes = 1 } = {}) {
|
playBroadcast(broadcast, options) {
|
||||||
const options = { volume, passes };
|
|
||||||
this.destroyCurrentStream();
|
this.destroyCurrentStream();
|
||||||
const dispatcher = this.createDispatcher(broadcast, options);
|
const dispatcher = this.createDispatcher(broadcast, options);
|
||||||
this.currentStream = {
|
this.currentStream = {
|
||||||
@@ -148,7 +156,9 @@ class AudioPlayer extends EventEmitter {
|
|||||||
return dispatcher;
|
return dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
createDispatcher(stream, options) {
|
createDispatcher(stream, { seek = 0, volume = 1, passes = 1 } = {}) {
|
||||||
|
const options = { seek, volume, passes };
|
||||||
|
|
||||||
const dispatcher = new StreamDispatcher(this, stream, options);
|
const dispatcher = new StreamDispatcher(this, stream, options);
|
||||||
dispatcher.on('end', () => this.destroyCurrentStream());
|
dispatcher.on('end', () => this.destroyCurrentStream());
|
||||||
dispatcher.on('error', () => this.destroyCurrentStream());
|
dispatcher.on('error', () => this.destroyCurrentStream());
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ nonce.fill(0);
|
|||||||
* Receives voice data from a voice connection.
|
* Receives voice data from a voice connection.
|
||||||
* ```js
|
* ```js
|
||||||
* // Obtained using:
|
* // Obtained using:
|
||||||
* voiceChannel.join().then(connection => {
|
* voiceChannel.join()
|
||||||
* const receiver = connection.createReceiver();
|
* .then(connection => {
|
||||||
* });
|
* const receiver = connection.createReceiver();
|
||||||
|
* });
|
||||||
* ```
|
* ```
|
||||||
* @extends {EventEmitter}
|
* @extends {EventEmitter}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const browser = require('os').platform() === 'browser';
|
const browser = typeof window !== 'undefined';
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const Constants = require('../../util/Constants');
|
const Constants = require('../../util/Constants');
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
@@ -29,12 +29,12 @@ const WebSocket = (function findWebSocket() {
|
|||||||
class WebSocketConnection extends EventEmitter {
|
class WebSocketConnection extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* @param {WebSocketManager} manager The WebSocket manager
|
* @param {WebSocketManager} manager The WebSocket manager
|
||||||
* @param {string} gateway WebSocket gateway to connect to
|
* @param {string} gateway The WebSocket gateway to connect to
|
||||||
*/
|
*/
|
||||||
constructor(manager, gateway) {
|
constructor(manager, gateway) {
|
||||||
super();
|
super();
|
||||||
/**
|
/**
|
||||||
* WebSocket Manager of this connection
|
* The WebSocket Manager of this connection
|
||||||
* @type {WebSocketManager}
|
* @type {WebSocketManager}
|
||||||
*/
|
*/
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
@@ -115,6 +115,10 @@ class WebSocketConnection extends EventEmitter {
|
|||||||
this.debug('Tried to mark self as ready, but already ready');
|
this.debug('Tried to mark self as ready, but already ready');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Emitted when the client becomes ready to start working.
|
||||||
|
* @event Client#ready
|
||||||
|
*/
|
||||||
this.status = Constants.Status.READY;
|
this.status = Constants.Status.READY;
|
||||||
this.client.emit(Constants.Events.READY);
|
this.client.emit(Constants.Events.READY);
|
||||||
this.packetManager.handleQueue();
|
this.packetManager.handleQueue();
|
||||||
@@ -228,7 +232,7 @@ class WebSocketConnection extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a connection to a gateway.
|
* Creates a connection to a gateway.
|
||||||
* @param {string} gateway Gateway to connect to
|
* @param {string} gateway The gateway to connect to
|
||||||
* @param {number} [after=0] How long to wait before connecting
|
* @param {number} [after=0] How long to wait before connecting
|
||||||
* @param {boolean} [force=false] Whether or not to force a new connection even if one already exists
|
* @param {boolean} [force=false] Whether or not to force a new connection even if one already exists
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@@ -280,12 +284,13 @@ class WebSocketConnection extends EventEmitter {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
onMessage(event) {
|
onMessage(event) {
|
||||||
|
let data;
|
||||||
try {
|
try {
|
||||||
event.data = this.unpack(event.data);
|
data = this.unpack(event.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.emit('debug', err);
|
this.emit('debug', err);
|
||||||
}
|
}
|
||||||
return this.onPacket(event.data);
|
return this.onPacket(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,11 +356,19 @@ class WebSocketConnection extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever an error occurs with the WebSocket.
|
* Called whenever an error occurs with the WebSocket.
|
||||||
* @param {Error} error Error that occurred
|
* @param {Error} error The error that occurred
|
||||||
*/
|
*/
|
||||||
onError(error) {
|
onError(error) {
|
||||||
|
if (error && error.message === 'uWs client connection error') {
|
||||||
|
this.reconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Emitted whenever the client's WebSocket encounters a connection error.
|
||||||
|
* @event Client#error
|
||||||
|
* @param {Error} error The encountered error
|
||||||
|
*/
|
||||||
this.client.emit(Constants.Events.ERROR, error);
|
this.client.emit(Constants.Events.ERROR, error);
|
||||||
if (error.message === 'uWs client connection error') this.reconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -431,7 +444,7 @@ class WebSocketConnection extends EventEmitter {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
identify(after) {
|
identify(after) {
|
||||||
if (after) return this.client.setTimeout(this.identify.apply(this), after);
|
if (after) return this.client.setTimeout(this.identify.bind(this), after);
|
||||||
return this.sessionID ? this.identifyResume() : this.identifyNew();
|
return this.sessionID ? this.identifyResume() : this.identifyNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const Constants = require('../../util/Constants');
|
|||||||
const WebSocketConnection = require('./WebSocketConnection');
|
const WebSocketConnection = require('./WebSocketConnection');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebSocket Manager of the client
|
* WebSocket Manager of the client.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
class WebSocketManager extends EventEmitter {
|
class WebSocketManager extends EventEmitter {
|
||||||
@@ -23,7 +23,7 @@ class WebSocketManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a heartbeat on the available connection
|
* Sends a heartbeat on the available connection.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
heartbeat() {
|
heartbeat() {
|
||||||
@@ -67,7 +67,7 @@ class WebSocketManager extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects the client to a gateway.
|
* Connects the client to a gateway.
|
||||||
* @param {string} gateway Gateway to connect to
|
* @param {string} gateway The gateway to connect to
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
connect(gateway) {
|
connect(gateway) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class WebSocketPacketManager {
|
|||||||
this.register(Constants.WSEvents.USER_UPDATE, require('./handlers/UserUpdate'));
|
this.register(Constants.WSEvents.USER_UPDATE, require('./handlers/UserUpdate'));
|
||||||
this.register(Constants.WSEvents.USER_NOTE_UPDATE, require('./handlers/UserNoteUpdate'));
|
this.register(Constants.WSEvents.USER_NOTE_UPDATE, require('./handlers/UserNoteUpdate'));
|
||||||
this.register(Constants.WSEvents.USER_SETTINGS_UPDATE, require('./handlers/UserSettingsUpdate'));
|
this.register(Constants.WSEvents.USER_SETTINGS_UPDATE, require('./handlers/UserSettingsUpdate'));
|
||||||
|
this.register(Constants.WSEvents.USER_GUILD_SETTINGS_UPDATE, require('./handlers/UserGuildSettingsUpdate'));
|
||||||
this.register(Constants.WSEvents.VOICE_STATE_UPDATE, require('./handlers/VoiceStateUpdate'));
|
this.register(Constants.WSEvents.VOICE_STATE_UPDATE, require('./handlers/VoiceStateUpdate'));
|
||||||
this.register(Constants.WSEvents.TYPING_START, require('./handlers/TypingStart'));
|
this.register(Constants.WSEvents.TYPING_START, require('./handlers/TypingStart'));
|
||||||
this.register(Constants.WSEvents.MESSAGE_CREATE, require('./handlers/MessageCreate'));
|
this.register(Constants.WSEvents.MESSAGE_CREATE, require('./handlers/MessageCreate'));
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class GuildMembersChunkHandler extends AbstractHandler {
|
|||||||
/**
|
/**
|
||||||
* Emitted whenever a chunk of guild members is received (all members come from the same guild).
|
* Emitted whenever a chunk of guild members is received (all members come from the same guild).
|
||||||
* @event Client#guildMembersChunk
|
* @event Client#guildMembersChunk
|
||||||
* @param {Collection<Snowflake, GuildMember>} members The members in the chunk
|
* @param {GuildMember[]} members The members in the chunk
|
||||||
* @param {Guild} guild The guild related to the member chunk
|
* @param {Guild} guild The guild related to the member chunk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class ReadyHandler extends AbstractHandler {
|
|||||||
client.ws.heartbeat();
|
client.ws.heartbeat();
|
||||||
|
|
||||||
data.user.user_settings = data.user_settings;
|
data.user.user_settings = data.user_settings;
|
||||||
|
data.user.user_guild_settings = data.user_guild_settings;
|
||||||
|
|
||||||
const clientUser = new ClientUser(client, data.user);
|
const clientUser = new ClientUser(client, data.user);
|
||||||
client.user = clientUser;
|
client.user = clientUser;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ResumedHandler extends AbstractHandler {
|
|||||||
const replayed = ws.sequence - ws.closeSequence;
|
const replayed = ws.sequence - ws.closeSequence;
|
||||||
|
|
||||||
ws.debug(`RESUMED ${ws._trace.join(' -> ')} | replayed ${replayed} events.`);
|
ws.debug(`RESUMED ${ws._trace.join(' -> ')} | replayed ${replayed} events.`);
|
||||||
client.emit('resume', replayed);
|
client.emit(Constants.Events.RESUME, replayed);
|
||||||
ws.heartbeat();
|
ws.heartbeat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const AbstractHandler = require('./AbstractHandler');
|
||||||
|
const Constants = require('../../../../util/Constants');
|
||||||
|
|
||||||
|
class UserGuildSettingsUpdateHandler extends AbstractHandler {
|
||||||
|
handle(packet) {
|
||||||
|
const client = this.packetManager.client;
|
||||||
|
client.user.guildSettings.get(packet.d.guild_id).patch(packet.d);
|
||||||
|
client.emit(Constants.Events.USER_GUILD_SETTINGS_UPDATE, client.user.guildSettings.get(packet.d.guild_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted whenever the client user's settings update.
|
||||||
|
* @event Client#clientUserGuildSettingsUpdate
|
||||||
|
* @param {ClientUserGuildSettings} clientUserGuildSettings The new client user guild settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = UserGuildSettingsUpdateHandler;
|
||||||
@@ -11,6 +11,7 @@ module.exports = {
|
|||||||
// Utilities
|
// Utilities
|
||||||
Collection: require('./util/Collection'),
|
Collection: require('./util/Collection'),
|
||||||
Constants: require('./util/Constants'),
|
Constants: require('./util/Constants'),
|
||||||
|
DiscordAPIError: require('./client/rest/DiscordAPIError'),
|
||||||
EvaluatedPermissions: require('./util/Permissions'),
|
EvaluatedPermissions: require('./util/Permissions'),
|
||||||
Permissions: require('./util/Permissions'),
|
Permissions: require('./util/Permissions'),
|
||||||
Snowflake: require('./util/Snowflake'),
|
Snowflake: require('./util/Snowflake'),
|
||||||
@@ -25,6 +26,7 @@ module.exports = {
|
|||||||
splitMessage: Util.splitMessage,
|
splitMessage: Util.splitMessage,
|
||||||
|
|
||||||
// Structures
|
// Structures
|
||||||
|
Attachment: require('./structures/Attachment'),
|
||||||
Channel: require('./structures/Channel'),
|
Channel: require('./structures/Channel'),
|
||||||
ClientUser: require('./structures/ClientUser'),
|
ClientUser: require('./structures/ClientUser'),
|
||||||
ClientUserSettings: require('./structures/ClientUserSettings'),
|
ClientUserSettings: require('./structures/ClientUserSettings'),
|
||||||
@@ -59,5 +61,3 @@ module.exports = {
|
|||||||
VoiceChannel: require('./structures/VoiceChannel'),
|
VoiceChannel: require('./structures/VoiceChannel'),
|
||||||
Webhook: require('./structures/Webhook'),
|
Webhook: require('./structures/Webhook'),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (require('os').platform() === 'browser') window.Discord = module.exports; // eslint-disable-line no-undef
|
|
||||||
|
|||||||
@@ -69,9 +69,11 @@ class Shard {
|
|||||||
* @param {string} prop Name of the client property to get, using periods for nesting
|
* @param {string} prop Name of the client property to get, using periods for nesting
|
||||||
* @returns {Promise<*>}
|
* @returns {Promise<*>}
|
||||||
* @example
|
* @example
|
||||||
* shard.fetchClientValue('guilds.size').then(count => {
|
* shard.fetchClientValue('guilds.size')
|
||||||
* console.log(`${count} guilds in shard ${shard.id}`);
|
* .then(count => {
|
||||||
* }).catch(console.error);
|
* console.log(`${count} guilds in shard ${shard.id}`);
|
||||||
|
* })
|
||||||
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchClientValue(prop) {
|
fetchClientValue(prop) {
|
||||||
if (this._fetches.has(prop)) return this._fetches.get(prop);
|
if (this._fetches.has(prop)) return this._fetches.get(prop);
|
||||||
|
|||||||
@@ -49,9 +49,11 @@ class ShardClientUtil {
|
|||||||
* @param {string} prop Name of the client property to get, using periods for nesting
|
* @param {string} prop Name of the client property to get, using periods for nesting
|
||||||
* @returns {Promise<Array>}
|
* @returns {Promise<Array>}
|
||||||
* @example
|
* @example
|
||||||
* client.shard.fetchClientValues('guilds.size').then(results => {
|
* client.shard.fetchClientValues('guilds.size')
|
||||||
* console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`);
|
* .then(results => {
|
||||||
* }).catch(console.error);
|
* console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`);
|
||||||
|
* })
|
||||||
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchClientValues(prop) {
|
fetchClientValues(prop) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
@@ -176,9 +176,11 @@ class ShardingManager extends EventEmitter {
|
|||||||
* @param {string} prop Name of the client property to get, using periods for nesting
|
* @param {string} prop Name of the client property to get, using periods for nesting
|
||||||
* @returns {Promise<Array>}
|
* @returns {Promise<Array>}
|
||||||
* @example
|
* @example
|
||||||
* manager.fetchClientValues('guilds.size').then(results => {
|
* manager.fetchClientValues('guilds.size')
|
||||||
* console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`);
|
* .then(results => {
|
||||||
* }).catch(console.error);
|
* console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`);
|
||||||
|
* })
|
||||||
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchClientValues(prop) {
|
fetchClientValues(prop) {
|
||||||
if (this.shards.size === 0) return Promise.reject(new Error('No shards have been spawned.'));
|
if (this.shards.size === 0) return Promise.reject(new Error('No shards have been spawned.'));
|
||||||
|
|||||||
75
src/structures/Attachment.js
Normal file
75
src/structures/Attachment.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* Represents an attachment in a message.
|
||||||
|
* @param {BufferResolvable|Stream} file The file
|
||||||
|
* @param {string} [name] The name of the file, if any
|
||||||
|
*/
|
||||||
|
class Attachment {
|
||||||
|
constructor(file, name) {
|
||||||
|
this.file = null;
|
||||||
|
if (name) this.setAttachment(file, name);
|
||||||
|
else this._attach(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get name() {
|
||||||
|
return this.file.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file
|
||||||
|
* @type {?BufferResolvable|Stream}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get attachment() {
|
||||||
|
return this.file.attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file of this attachment.
|
||||||
|
* @param {BufferResolvable|Stream} file The file
|
||||||
|
* @param {string} name The name of the file
|
||||||
|
* @returns {Attachment} This attachment
|
||||||
|
*/
|
||||||
|
setAttachment(file, name) {
|
||||||
|
this.file = { attachment: file, name };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file of this attachment.
|
||||||
|
* @param {BufferResolvable|Stream} attachment The file
|
||||||
|
* @returns {Attachment} This attachment
|
||||||
|
*/
|
||||||
|
setFile(attachment) {
|
||||||
|
this.file = { attachment };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of this attachment.
|
||||||
|
* @param {string} name The name of the image
|
||||||
|
* @returns {Attachment} This attachment
|
||||||
|
*/
|
||||||
|
setName(name) {
|
||||||
|
this.file.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file of this attachment.
|
||||||
|
* @param {BufferResolvable|Stream} file The file
|
||||||
|
* @param {string} name The name of the file
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_attach(file, name) {
|
||||||
|
if (typeof file === 'string') this.file = file;
|
||||||
|
else this.setAttachment(file, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Attachment;
|
||||||
@@ -58,8 +58,8 @@ class Channel {
|
|||||||
* @example
|
* @example
|
||||||
* // Delete the channel
|
* // Delete the channel
|
||||||
* channel.delete()
|
* channel.delete()
|
||||||
* .then() // Success
|
* .then() // Success
|
||||||
* .catch(console.error); // Log error
|
* .catch(console.error); // Log error
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete() {
|
||||||
return this.client.rest.methods.deleteChannel(this);
|
return this.client.rest.methods.deleteChannel(this);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const User = require('./User');
|
const User = require('./User');
|
||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
const ClientUserSettings = require('./ClientUserSettings');
|
const ClientUserSettings = require('./ClientUserSettings');
|
||||||
|
const ClientUserGuildSettings = require('./ClientUserGuildSettings');
|
||||||
const Constants = require('../util/Constants');
|
const Constants = require('../util/Constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,7 +73,19 @@ class ClientUser extends User {
|
|||||||
* <warn>This is only filled when using a user account.</warn>
|
* <warn>This is only filled when using a user account.</warn>
|
||||||
* @type {?ClientUserSettings}
|
* @type {?ClientUserSettings}
|
||||||
*/
|
*/
|
||||||
if (data.user_settings) this.settings = new ClientUserSettings(this, data.user_settings);
|
this.settings = data.user_settings ? new ClientUserSettings(this, data.user_settings) : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All of the user's guild settings
|
||||||
|
* <warn>This is only filled when using a user account</warn>
|
||||||
|
* @type {Collection<Snowflake, ClientUserGuildSettings>}
|
||||||
|
*/
|
||||||
|
this.guildSettings = new Collection();
|
||||||
|
if (data.user_guild_settings) {
|
||||||
|
for (const settings of data.user_guild_settings) {
|
||||||
|
this.guildSettings.set(settings.guild_id, new ClientUserGuildSettings(settings, this.client));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
edit(data) {
|
edit(data) {
|
||||||
@@ -89,8 +102,8 @@ class ClientUser extends User {
|
|||||||
* @example
|
* @example
|
||||||
* // Set username
|
* // Set username
|
||||||
* client.user.setUsername('discordjs')
|
* client.user.setUsername('discordjs')
|
||||||
* .then(user => console.log(`My new username is ${user.username}`))
|
* .then(user => console.log(`My new username is ${user.username}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setUsername(username, password) {
|
setUsername(username, password) {
|
||||||
return this.client.rest.methods.updateCurrentUser({ username }, password);
|
return this.client.rest.methods.updateCurrentUser({ username }, password);
|
||||||
@@ -105,8 +118,8 @@ class ClientUser extends User {
|
|||||||
* @example
|
* @example
|
||||||
* // Set email
|
* // Set email
|
||||||
* client.user.setEmail('bob@gmail.com', 'some amazing password 123')
|
* client.user.setEmail('bob@gmail.com', 'some amazing password 123')
|
||||||
* .then(user => console.log(`My new email is ${user.email}`))
|
* .then(user => console.log(`My new email is ${user.email}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setEmail(email, password) {
|
setEmail(email, password) {
|
||||||
return this.client.rest.methods.updateCurrentUser({ email }, password);
|
return this.client.rest.methods.updateCurrentUser({ email }, password);
|
||||||
@@ -121,8 +134,8 @@ class ClientUser extends User {
|
|||||||
* @example
|
* @example
|
||||||
* // Set password
|
* // Set password
|
||||||
* client.user.setPassword('some new amazing password 456', 'some amazing password 123')
|
* client.user.setPassword('some new amazing password 456', 'some amazing password 123')
|
||||||
* .then(user => console.log('New password set!'))
|
* .then(user => console.log('New password set!'))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setPassword(newPassword, oldPassword) {
|
setPassword(newPassword, oldPassword) {
|
||||||
return this.client.rest.methods.updateCurrentUser({ password: newPassword }, oldPassword);
|
return this.client.rest.methods.updateCurrentUser({ password: newPassword }, oldPassword);
|
||||||
@@ -135,17 +148,13 @@ class ClientUser extends User {
|
|||||||
* @example
|
* @example
|
||||||
* // Set avatar
|
* // Set avatar
|
||||||
* client.user.setAvatar('./avatar.png')
|
* client.user.setAvatar('./avatar.png')
|
||||||
* .then(user => console.log(`New avatar set!`))
|
* .then(user => console.log(`New avatar set!`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setAvatar(avatar) {
|
setAvatar(avatar) {
|
||||||
if (typeof avatar === 'string' && avatar.startsWith('data:')) {
|
return this.client.resolver.resolveImage(avatar).then(data =>
|
||||||
return this.client.rest.methods.updateCurrentUser({ avatar });
|
this.client.rest.methods.updateCurrentUser({ avatar: data })
|
||||||
} else {
|
);
|
||||||
return this.client.resolver.resolveBuffer(avatar).then(data =>
|
|
||||||
this.client.rest.methods.updateCurrentUser({ avatar: data })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,7 +199,7 @@ class ClientUser extends User {
|
|||||||
|
|
||||||
if (data.game) {
|
if (data.game) {
|
||||||
game = data.game;
|
game = data.game;
|
||||||
if (game.url) game.type = 1;
|
game.type = game.url ? 1 : 0;
|
||||||
} else if (typeof data.game !== 'undefined') {
|
} else if (typeof data.game !== 'undefined') {
|
||||||
game = null;
|
game = null;
|
||||||
}
|
}
|
||||||
@@ -215,10 +224,10 @@ class ClientUser extends User {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A user's status. Must be one of:
|
* A user's status. Must be one of:
|
||||||
* - `online`
|
* * `online`
|
||||||
* - `idle`
|
* * `idle`
|
||||||
* - `invisible`
|
* * `invisible`
|
||||||
* - `dnd` (do not disturb)
|
* * `dnd` (do not disturb)
|
||||||
* @typedef {string} PresenceStatus
|
* @typedef {string} PresenceStatus
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -265,7 +274,7 @@ class ClientUser extends User {
|
|||||||
* @param {Guild|Snowflake} [options.guild] Limit the search to a specific guild
|
* @param {Guild|Snowflake} [options.guild] Limit the search to a specific guild
|
||||||
* @returns {Promise<Message[]>}
|
* @returns {Promise<Message[]>}
|
||||||
*/
|
*/
|
||||||
fetchMentions(options = { limit: 25, roles: true, everyone: true, guild: null }) {
|
fetchMentions(options = {}) {
|
||||||
return this.client.rest.methods.fetchMentions(options);
|
return this.client.rest.methods.fetchMentions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,16 +304,15 @@ class ClientUser extends User {
|
|||||||
* Creates a guild.
|
* Creates a guild.
|
||||||
* <warn>This is only available when using a user account.</warn>
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @param {string} name The name of the guild
|
* @param {string} name The name of the guild
|
||||||
* @param {string} region The region for the server
|
* @param {string} [region] The region for the server
|
||||||
* @param {BufferResolvable|Base64Resolvable} [icon=null] The icon for the guild
|
* @param {BufferResolvable|Base64Resolvable} [icon=null] The icon for the guild
|
||||||
* @returns {Promise<Guild>} The guild that was created
|
* @returns {Promise<Guild>} The guild that was created
|
||||||
*/
|
*/
|
||||||
createGuild(name, region, icon = null) {
|
createGuild(name, region, icon = null) {
|
||||||
if (!icon) return this.client.rest.methods.createGuild({ name, icon, region });
|
|
||||||
if (typeof icon === 'string' && icon.startsWith('data:')) {
|
if (typeof icon === 'string' && icon.startsWith('data:')) {
|
||||||
return this.client.rest.methods.createGuild({ name, icon, region });
|
return this.client.rest.methods.createGuild({ name, icon, region });
|
||||||
} else {
|
} else {
|
||||||
return this.client.resolver.resolveBuffer(icon).then(data =>
|
return this.client.resolver.resolveImage(icon).then(data =>
|
||||||
this.client.rest.methods.createGuild({ name, icon: data, region })
|
this.client.rest.methods.createGuild({ name, icon: data, region })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/structures/ClientUserChannelOverride.js
Normal file
30
src/structures/ClientUserChannelOverride.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const Constants = require('../util/Constants');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the ClientUser's channel overrides.
|
||||||
|
*/
|
||||||
|
class ClientUserChannelOverride {
|
||||||
|
constructor(data) {
|
||||||
|
this.patch(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch the data contained in this class with new partial data.
|
||||||
|
* @param {Object} data Data to patch this with
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
patch(data) {
|
||||||
|
for (const key of Object.keys(Constants.UserChannelOverrideMap)) {
|
||||||
|
const value = Constants.UserChannelOverrideMap[key];
|
||||||
|
if (!data.hasOwnProperty(key)) continue;
|
||||||
|
if (typeof value === 'function') {
|
||||||
|
this[value.name] = value(data[key]);
|
||||||
|
} else {
|
||||||
|
this[value] = data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ClientUserChannelOverride;
|
||||||
60
src/structures/ClientUserGuildSettings.js
Normal file
60
src/structures/ClientUserGuildSettings.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
const Constants = require('../util/Constants');
|
||||||
|
const Collection = require('../util/Collection');
|
||||||
|
const ClientUserChannelOverride = require('./ClientUserChannelOverride');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the ClientUser's guild settings.
|
||||||
|
*/
|
||||||
|
class ClientUserGuildSettings {
|
||||||
|
constructor(data, client) {
|
||||||
|
/**
|
||||||
|
* The client that created the instance of the ClientUserGuildSettings
|
||||||
|
* @name ClientUserGuildSettings#client
|
||||||
|
* @type {Client}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'client', { value: client });
|
||||||
|
/**
|
||||||
|
* The ID of the guild this settings are for
|
||||||
|
* @type {Snowflake}
|
||||||
|
*/
|
||||||
|
this.guildID = data.guild_id;
|
||||||
|
this.channelOverrides = new Collection();
|
||||||
|
this.patch(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch the data contained in this class with new partial data.
|
||||||
|
* @param {Object} data Data to patch this with
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
patch(data) {
|
||||||
|
for (const key of Object.keys(Constants.UserGuildSettingsMap)) {
|
||||||
|
const value = Constants.UserGuildSettingsMap[key];
|
||||||
|
if (!data.hasOwnProperty(key)) continue;
|
||||||
|
if (key === 'channel_overrides') {
|
||||||
|
for (const channel of data[key]) {
|
||||||
|
this.channelOverrides.set(channel.channel_id,
|
||||||
|
new ClientUserChannelOverride(channel));
|
||||||
|
}
|
||||||
|
} else if (typeof value === 'function') {
|
||||||
|
this[value.name] = value(data[key]);
|
||||||
|
} else {
|
||||||
|
this[value] = data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a specific property of the guild settings.
|
||||||
|
* @param {string} name Name of property
|
||||||
|
* @param {value} value Value to patch
|
||||||
|
* @returns {Promise<Object>}
|
||||||
|
*/
|
||||||
|
update(name, value) {
|
||||||
|
return this.client.rest.methods.patchClientUserGuildSettings(this.guildID, { [name]: value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ClientUserGuildSettings;
|
||||||
@@ -13,6 +13,8 @@ class ClientUserSettings {
|
|||||||
/**
|
/**
|
||||||
* Patch the data contained in this class with new partial data.
|
* Patch the data contained in this class with new partial data.
|
||||||
* @param {Object} data Data to patch this with
|
* @param {Object} data Data to patch this with
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
patch(data) {
|
patch(data) {
|
||||||
for (const key of Object.keys(Constants.UserSettingsMap)) {
|
for (const key of Object.keys(Constants.UserSettingsMap)) {
|
||||||
@@ -29,7 +31,7 @@ class ClientUserSettings {
|
|||||||
/**
|
/**
|
||||||
* Update a specific property of of user settings.
|
* Update a specific property of of user settings.
|
||||||
* @param {string} name Name of property
|
* @param {string} name Name of property
|
||||||
* @param {value} value Value to patch
|
* @param {*} value Value to patch
|
||||||
* @returns {Promise<Object>}
|
* @returns {Promise<Object>}
|
||||||
*/
|
*/
|
||||||
update(name, value) {
|
update(name, value) {
|
||||||
@@ -37,6 +39,7 @@ class ClientUserSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Sets the position at which this guild will appear in the Discord client.
|
||||||
* @param {Guild} guild The guild to move
|
* @param {Guild} guild The guild to move
|
||||||
* @param {number} position Absolute or relative position
|
* @param {number} position Absolute or relative position
|
||||||
* @param {boolean} [relative=false] Whether to position relatively or absolutely
|
* @param {boolean} [relative=false] Whether to position relatively or absolutely
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class DMChannel extends Channel {
|
|||||||
get typing() {}
|
get typing() {}
|
||||||
get typingCount() {}
|
get typingCount() {}
|
||||||
createCollector() {}
|
createCollector() {}
|
||||||
|
createMessageCollector() {}
|
||||||
awaitMessages() {}
|
awaitMessages() {}
|
||||||
// Doesn't work on DM channels; bulkDelete() {}
|
// Doesn't work on DM channels; bulkDelete() {}
|
||||||
acknowledge() {}
|
acknowledge() {}
|
||||||
|
|||||||
@@ -112,24 +112,26 @@ class Emoji {
|
|||||||
/**
|
/**
|
||||||
* Edits the emoji.
|
* Edits the emoji.
|
||||||
* @param {EmojiEditData} data The new data for the emoji
|
* @param {EmojiEditData} data The new data for the emoji
|
||||||
|
* @param {string} [reason] Reason for editing this emoji
|
||||||
* @returns {Promise<Emoji>}
|
* @returns {Promise<Emoji>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit a emoji
|
* // Edit an emoji
|
||||||
* emoji.edit({name: 'newemoji'})
|
* emoji.edit({name: 'newemoji'})
|
||||||
* .then(e => console.log(`Edited emoji ${e}`))
|
* .then(e => console.log(`Edited emoji ${e}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
edit(data) {
|
edit(data, reason) {
|
||||||
return this.client.rest.methods.updateEmoji(this, data);
|
return this.client.rest.methods.updateEmoji(this, data, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of the emoji.
|
* Set the name of the emoji.
|
||||||
* @param {string} name The new name for the emoji
|
* @param {string} name The new name for the emoji
|
||||||
|
* @param {string} [reason] The reason for changing the emoji's name
|
||||||
* @returns {Promise<Emoji>}
|
* @returns {Promise<Emoji>}
|
||||||
*/
|
*/
|
||||||
setName(name) {
|
setName(name, reason) {
|
||||||
return this.edit({ name });
|
return this.edit({ name }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const Channel = require('./Channel');
|
const Channel = require('./Channel');
|
||||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
|
const Constants = require('../util/Constants');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{ type: 3,
|
{ type: 3,
|
||||||
@@ -47,8 +48,8 @@ class GroupDMChannel extends Channel {
|
|||||||
this.name = data.name;
|
this.name = data.name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hash of the Group DM icon.
|
* A hash of this Group DM icon
|
||||||
* @type {string}
|
* @type {?string}
|
||||||
*/
|
*/
|
||||||
this.icon = data.icon;
|
this.icon = data.icon;
|
||||||
|
|
||||||
@@ -70,11 +71,13 @@ class GroupDMChannel extends Channel {
|
|||||||
*/
|
*/
|
||||||
this.applicationID = data.application_id;
|
this.applicationID = data.application_id;
|
||||||
|
|
||||||
/**
|
if (data.nicks) {
|
||||||
* Nicknames for group members
|
/**
|
||||||
* @type {?Collection<Snowflake, string>}
|
* Nicknames for group members
|
||||||
*/
|
* @type {?Collection<Snowflake, string>}
|
||||||
if (data.nicks) this.nicks = new Collection(data.nicks.map(n => [n.id, n.nick]));
|
*/
|
||||||
|
this.nicks = new Collection(data.nicks.map(n => [n.id, n.nick]));
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.recipients) {
|
if (!this.recipients) {
|
||||||
/**
|
/**
|
||||||
@@ -103,6 +106,23 @@ class GroupDMChannel extends Channel {
|
|||||||
return this.client.users.get(this.ownerID);
|
return this.client.users.get(this.ownerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to this guild's icon
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get iconURL() {
|
||||||
|
if (!this.icon) return null;
|
||||||
|
return Constants.Endpoints.Channel(this).Icon(this.client.options.http.cdn, this.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
edit(data) {
|
||||||
|
const _data = {};
|
||||||
|
if (data.name) _data.name = data.name;
|
||||||
|
if (typeof data.icon !== 'undefined') _data.icon = data.icon;
|
||||||
|
return this.client.rest.methods.updateGroupDMChannel(this, _data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this channel equals another channel. It compares all properties, so for most operations
|
* Whether this channel equals another channel. It compares all properties, so for most operations
|
||||||
* it is advisable to just compare `channel.id === channel2.id` as it is much faster and is often
|
* it is advisable to just compare `channel.id === channel2.id` as it is much faster and is often
|
||||||
@@ -128,6 +148,7 @@ class GroupDMChannel extends Channel {
|
|||||||
* Add a user to the DM
|
* Add a user to the DM
|
||||||
* @param {UserResolvable|string} accessTokenOrID Access token or user resolvable
|
* @param {UserResolvable|string} accessTokenOrID Access token or user resolvable
|
||||||
* @param {string} [nick] Permanent nickname to give the user (only available if a bot is creating the DM)
|
* @param {string} [nick] Permanent nickname to give the user (only available if a bot is creating the DM)
|
||||||
|
* @returns {Promise<GroupDMChannel>}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
addUser(accessTokenOrID, nick) {
|
addUser(accessTokenOrID, nick) {
|
||||||
@@ -138,6 +159,39 @@ class GroupDMChannel extends Channel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new GroupDMChannel icon.
|
||||||
|
* @param {Base64Resolvable|BufferResolvable} icon The new icon of the group dm
|
||||||
|
* @returns {Promise<GroupDMChannel>}
|
||||||
|
* @example
|
||||||
|
* // Edit the group dm icon
|
||||||
|
* channel.setIcon('./icon.png')
|
||||||
|
* .then(updated => console.log('Updated the channel icon'))
|
||||||
|
* .catch(console.error);
|
||||||
|
*/
|
||||||
|
setIcon(icon) {
|
||||||
|
return this.client.resolver.resolveImage(icon).then(data => this.edit({ icon: data }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a new name for this Group DM.
|
||||||
|
* @param {string} name New name for this Group DM
|
||||||
|
* @returns {Promise<GroupDMChannel>}
|
||||||
|
*/
|
||||||
|
setName(name) {
|
||||||
|
return this.edit({ name });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an user from this Group DM.
|
||||||
|
* @param {UserResolvable} user User to remove
|
||||||
|
* @returns {Promise<GroupDMChannel>}
|
||||||
|
*/
|
||||||
|
removeUser(user) {
|
||||||
|
const id = this.client.resolver.resolveUserID(user);
|
||||||
|
return this.client.rest.methods.removeUserFromGroupDM(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When concatenated with a string, this automatically concatenates the channel's name instead of the Channel object.
|
* When concatenated with a string, this automatically concatenates the channel's name instead of the Channel object.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
@@ -169,6 +223,7 @@ class GroupDMChannel extends Channel {
|
|||||||
get typing() {}
|
get typing() {}
|
||||||
get typingCount() {}
|
get typingCount() {}
|
||||||
createCollector() {}
|
createCollector() {}
|
||||||
|
createMessageCollector() {}
|
||||||
awaitMessages() {}
|
awaitMessages() {}
|
||||||
// Doesn't work on Group DMs; bulkDelete() {}
|
// Doesn't work on Group DMs; bulkDelete() {}
|
||||||
acknowledge() {}
|
acknowledge() {}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
const util = require('util');
|
||||||
const Long = require('long');
|
const Long = require('long');
|
||||||
const User = require('./User');
|
const User = require('./User');
|
||||||
const Role = require('./Role');
|
const Role = require('./Role');
|
||||||
@@ -17,7 +18,7 @@ const Snowflake = require('../util/Snowflake');
|
|||||||
class Guild {
|
class Guild {
|
||||||
constructor(client, data) {
|
constructor(client, data) {
|
||||||
/**
|
/**
|
||||||
* The client that created the instance of the the guild
|
* The client that created the instance of the guild
|
||||||
* @name Guild#client
|
* @name Guild#client
|
||||||
* @type {Client}
|
* @type {Client}
|
||||||
* @readonly
|
* @readonly
|
||||||
@@ -62,8 +63,8 @@ class Guild {
|
|||||||
*/
|
*/
|
||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
} else {
|
} else {
|
||||||
this.available = true;
|
|
||||||
this.setup(data);
|
this.setup(data);
|
||||||
|
if (!data.channels) this.available = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +134,12 @@ class Guild {
|
|||||||
*/
|
*/
|
||||||
this.afkChannelID = data.afk_channel_id;
|
this.afkChannelID = data.afk_channel_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the system channel
|
||||||
|
* @type {?Snowflake}
|
||||||
|
*/
|
||||||
|
this.systemChannelID = data.system_channel_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether embedded images are enabled on this guild
|
* Whether embedded images are enabled on this guild
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -212,7 +219,8 @@ class Guild {
|
|||||||
|
|
||||||
if (!this.emojis) {
|
if (!this.emojis) {
|
||||||
/**
|
/**
|
||||||
* A collection of emojis that are in this guild. The key is the emoji's ID, the value is the emoji.
|
* A collection of emojis that are in this guild
|
||||||
|
* The key is the emoji's ID, the value is the emoji
|
||||||
* @type {Collection<Snowflake, Emoji>}
|
* @type {Collection<Snowflake, Emoji>}
|
||||||
*/
|
*/
|
||||||
this.emojis = new Collection();
|
this.emojis = new Collection();
|
||||||
@@ -262,6 +270,15 @@ class Guild {
|
|||||||
return Constants.Endpoints.Guild(this).Icon(this.client.options.http.cdn, this.icon);
|
return Constants.Endpoints.Guild(this).Icon(this.client.options.http.cdn, this.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The acronym that shows up in place of a guild icon.
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get nameAcronym() {
|
||||||
|
return this.name.replace(/\w+/g, name => name[0]).replace(/\s/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL to this guild's splash
|
* The URL to this guild's splash
|
||||||
* @type {?string}
|
* @type {?string}
|
||||||
@@ -281,6 +298,24 @@ class Guild {
|
|||||||
return this.members.get(this.ownerID);
|
return this.members.get(this.ownerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AFK voice channel for this guild
|
||||||
|
* @type {?VoiceChannel}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get afkChannel() {
|
||||||
|
return this.client.channels.get(this.afkChannelID) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System channel for this guild
|
||||||
|
* @type {?GuildChannel}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get systemChannel() {
|
||||||
|
return this.client.channels.get(this.systemChannelID) || null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the client is connected to any voice channel in this guild, this will be the relevant VoiceConnection
|
* If the client is connected to any voice channel in this guild, this will be the relevant VoiceConnection
|
||||||
* @type {?VoiceConnection}
|
* @type {?VoiceConnection}
|
||||||
@@ -291,19 +326,11 @@ class Guild {
|
|||||||
return this.client.voice.connections.get(this.id) || null;
|
return this.client.voice.connections.get(this.id) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The `#general` TextChannel of the guild
|
|
||||||
* @type {TextChannel}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get defaultChannel() {
|
|
||||||
return this.channels.get(this.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The position of this guild
|
* The position of this guild
|
||||||
* <warn>This is only available when using a user account.</warn>
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @type {?number}
|
* @type {?number}
|
||||||
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get position() {
|
get position() {
|
||||||
if (this.client.user.bot) return null;
|
if (this.client.user.bot) return null;
|
||||||
@@ -311,6 +338,66 @@ class Guild {
|
|||||||
return this.client.user.settings.guildPositions.indexOf(this.id);
|
return this.client.user.settings.guildPositions.indexOf(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the guild is muted
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
|
* @type {?boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get muted() {
|
||||||
|
if (this.client.user.bot) return null;
|
||||||
|
try {
|
||||||
|
return this.client.user.guildSettings.get(this.id).muted;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of message that should notify you
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
|
* @type {?MessageNotificationType}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get messageNotifications() {
|
||||||
|
if (this.client.user.bot) return null;
|
||||||
|
try {
|
||||||
|
return this.client.user.guildSettings.get(this.id).messageNotifications;
|
||||||
|
} catch (err) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to receive mobile push notifications
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
|
* @type {?boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get mobilePush() {
|
||||||
|
if (this.client.user.bot) return null;
|
||||||
|
try {
|
||||||
|
return this.client.user.guildSettings.get(this.id).mobilePush;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to suppress everyone messages
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
|
* @type {?boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get suppressEveryone() {
|
||||||
|
if (this.client.user.bot) return null;
|
||||||
|
try {
|
||||||
|
return this.client.user.guildSettings.get(this.id).suppressEveryone;
|
||||||
|
} catch (err) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `@everyone` role of the guild
|
* The `@everyone` role of the guild
|
||||||
* @type {Role}
|
* @type {Role}
|
||||||
@@ -366,7 +453,8 @@ class Guild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a collection of invites to this guild. Resolves with a collection mapping invites by their codes.
|
* Fetch a collection of invites to this guild.
|
||||||
|
* Resolves with a collection mapping invites by their codes.
|
||||||
* @returns {Promise<Collection<string, Invite>>}
|
* @returns {Promise<Collection<string, Invite>>}
|
||||||
*/
|
*/
|
||||||
fetchInvites() {
|
fetchInvites() {
|
||||||
@@ -424,7 +512,7 @@ class Guild {
|
|||||||
/**
|
/**
|
||||||
* Fetch a single guild member from a user.
|
* Fetch a single guild member from a user.
|
||||||
* @param {UserResolvable} user The user to fetch the member for
|
* @param {UserResolvable} user The user to fetch the member for
|
||||||
* @param {boolean} [cache=true] Insert the user into the users cache
|
* @param {boolean} [cache=true] Insert the member into the members cache
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
fetchMember(user, cache = true) {
|
fetchMember(user, cache = true) {
|
||||||
@@ -475,9 +563,7 @@ class Guild {
|
|||||||
* Performs a search within the entire guild.
|
* Performs a search within the entire guild.
|
||||||
* <warn>This is only available when using a user account.</warn>
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
||||||
* @returns {Promise<Array<Message[]>>}
|
* @returns {Promise<MessageSearchResult>}
|
||||||
* An array containing arrays of messages. Each inner array is a search context cluster.
|
|
||||||
* The message which has triggered the result will have the `hit` property set to `true`.
|
|
||||||
* @example
|
* @example
|
||||||
* guild.search({
|
* guild.search({
|
||||||
* content: 'discord.js',
|
* content: 'discord.js',
|
||||||
@@ -497,7 +583,9 @@ class Guild {
|
|||||||
* @property {string} [name] The name of the guild
|
* @property {string} [name] The name of the guild
|
||||||
* @property {string} [region] The region of the guild
|
* @property {string} [region] The region of the guild
|
||||||
* @property {number} [verificationLevel] The verification level of the guild
|
* @property {number} [verificationLevel] The verification level of the guild
|
||||||
|
* @property {number} [explicitContentFilter] The level of the explicit content filter
|
||||||
* @property {ChannelResolvable} [afkChannel] The AFK channel of the guild
|
* @property {ChannelResolvable} [afkChannel] The AFK channel of the guild
|
||||||
|
* @property {ChannelResolvable} [systemChannel] The system channel of the guild
|
||||||
* @property {number} [afkTimeout] The AFK timeout of the guild
|
* @property {number} [afkTimeout] The AFK timeout of the guild
|
||||||
* @property {Base64Resolvable} [icon] The icon of the guild
|
* @property {Base64Resolvable} [icon] The icon of the guild
|
||||||
* @property {GuildMemberResolvable} [owner] The owner of the guild
|
* @property {GuildMemberResolvable} [owner] The owner of the guild
|
||||||
@@ -507,23 +595,52 @@ class Guild {
|
|||||||
/**
|
/**
|
||||||
* Updates the guild with new information - e.g. a new name.
|
* Updates the guild with new information - e.g. a new name.
|
||||||
* @param {GuildEditData} data The data to update the guild with
|
* @param {GuildEditData} data The data to update the guild with
|
||||||
|
* @param {string} [reason] Reason for editing the guild
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the guild name and region
|
* // Set the guild name and region
|
||||||
* guild.edit({
|
* guild.edit({
|
||||||
* name: 'Discord Guild',
|
* name: 'Discord Guild',
|
||||||
* region: 'london',
|
* region: 'london',
|
||||||
* })
|
* })
|
||||||
* .then(updated => console.log(`New guild name ${updated.name} in region ${updated.region}`))
|
* .then(updated => console.log(`New guild name ${updated.name} in region ${updated.region}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
edit(data) {
|
edit(data, reason) {
|
||||||
return this.client.rest.methods.updateGuild(this, data);
|
const _data = {};
|
||||||
|
if (data.name) _data.name = data.name;
|
||||||
|
if (data.region) _data.region = data.region;
|
||||||
|
if (typeof data.verificationLevel !== 'undefined') _data.verification_level = Number(data.verificationLevel);
|
||||||
|
if (typeof data.afkChannel !== 'undefined') {
|
||||||
|
_data.afk_channel_id = this.client.resolver.resolveChannelID(data.afkChannel);
|
||||||
|
}
|
||||||
|
if (typeof data.systemChannel !== 'undefined') {
|
||||||
|
_data.system_channel_id = this.client.resolver.resolveChannelID(data.systemChannel);
|
||||||
|
}
|
||||||
|
if (data.afkTimeout) _data.afk_timeout = Number(data.afkTimeout);
|
||||||
|
if (typeof data.icon !== 'undefined') _data.icon = data.icon;
|
||||||
|
if (data.owner) _data.owner_id = this.client.resolver.resolveUser(data.owner).id;
|
||||||
|
if (typeof data.splash !== 'undefined') _data.splash = data.splash;
|
||||||
|
if (typeof data.explicitContentFilter !== 'undefined') {
|
||||||
|
_data.explicit_content_filter = Number(data.explicitContentFilter);
|
||||||
|
}
|
||||||
|
return this.client.rest.methods.updateGuild(this, _data, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit the level of the explicit content filter.
|
||||||
|
* @param {number} explicitContentFilter The new level of the explicit content filter
|
||||||
|
* @param {string} [reason] Reason for changing the level of the guild's explicit content filter
|
||||||
|
* @returns {Promise<Guild>}
|
||||||
|
*/
|
||||||
|
setExplicitContentFilter(explicitContentFilter, reason) {
|
||||||
|
return this.edit({ explicitContentFilter }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the name of the guild.
|
* Edit the name of the guild.
|
||||||
* @param {string} name The new name of the guild
|
* @param {string} name The new name of the guild
|
||||||
|
* @param {string} [reason] Reason for changing the guild's name
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild name
|
* // Edit the guild name
|
||||||
@@ -531,13 +648,14 @@ class Guild {
|
|||||||
* .then(updated => console.log(`Updated guild name to ${guild.name}`))
|
* .then(updated => console.log(`Updated guild name to ${guild.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setName(name) {
|
setName(name, reason) {
|
||||||
return this.edit({ name });
|
return this.edit({ name }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the region of the guild.
|
* Edit the region of the guild.
|
||||||
* @param {string} region The new region of the guild
|
* @param {string} region The new region of the guild
|
||||||
|
* @param {string} [reason] Reason for changing the guild's region
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild region
|
* // Edit the guild region
|
||||||
@@ -545,13 +663,14 @@ class Guild {
|
|||||||
* .then(updated => console.log(`Updated guild region to ${guild.region}`))
|
* .then(updated => console.log(`Updated guild region to ${guild.region}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setRegion(region) {
|
setRegion(region, reason) {
|
||||||
return this.edit({ region });
|
return this.edit({ region }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the verification level of the guild.
|
* Edit the verification level of the guild.
|
||||||
* @param {number} verificationLevel The new verification level of the guild
|
* @param {number} verificationLevel The new verification level of the guild
|
||||||
|
* @param {string} [reason] Reason for changing the guild's verification level
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild verification level
|
* // Edit the guild verification level
|
||||||
@@ -559,13 +678,14 @@ class Guild {
|
|||||||
* .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`))
|
* .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setVerificationLevel(verificationLevel) {
|
setVerificationLevel(verificationLevel, reason) {
|
||||||
return this.edit({ verificationLevel });
|
return this.edit({ verificationLevel }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the AFK channel of the guild.
|
* Edit the AFK channel of the guild.
|
||||||
* @param {ChannelResolvable} afkChannel The new AFK channel
|
* @param {ChannelResolvable} afkChannel The new AFK channel
|
||||||
|
* @param {string} [reason] Reason for changing the guild's AFK channel
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild AFK channel
|
* // Edit the guild AFK channel
|
||||||
@@ -573,13 +693,24 @@ class Guild {
|
|||||||
* .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel}`))
|
* .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setAFKChannel(afkChannel) {
|
setAFKChannel(afkChannel, reason) {
|
||||||
return this.edit({ afkChannel });
|
return this.edit({ afkChannel }, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit the system channel of the guild.
|
||||||
|
* @param {ChannelResolvable} systemChannel The new system channel
|
||||||
|
* @param {string} [reason] Reason for changing the guild's system channel
|
||||||
|
* @returns {Promise<Guild>}
|
||||||
|
*/
|
||||||
|
setSystemChannel(systemChannel, reason) {
|
||||||
|
return this.edit({ systemChannel }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the AFK timeout of the guild.
|
* Edit the AFK timeout of the guild.
|
||||||
* @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK
|
* @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK
|
||||||
|
* @param {string} [reason] Reason for changing the guild's AFK timeout
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild AFK channel
|
* // Edit the guild AFK channel
|
||||||
@@ -587,27 +718,29 @@ class Guild {
|
|||||||
* .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`))
|
* .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setAFKTimeout(afkTimeout) {
|
setAFKTimeout(afkTimeout, reason) {
|
||||||
return this.edit({ afkTimeout });
|
return this.edit({ afkTimeout }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a new guild icon.
|
* Set a new guild icon.
|
||||||
* @param {Base64Resolvable} icon The new icon of the guild
|
* @param {Base64Resolvable|BufferResolvable} icon The new icon of the guild
|
||||||
|
* @param {string} [reason] Reason for changing the guild's icon
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild icon
|
* // Edit the guild icon
|
||||||
* guild.setIcon(fs.readFileSync('./icon.png'))
|
* guild.setIcon('./icon.png')
|
||||||
* .then(updated => console.log('Updated the guild icon'))
|
* .then(updated => console.log('Updated the guild icon'))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setIcon(icon) {
|
setIcon(icon, reason) {
|
||||||
return this.edit({ icon });
|
return this.client.resolver.resolveImage(icon).then(data => this.edit({ icon: data, reason }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new owner of the guild.
|
* Sets a new owner of the guild.
|
||||||
* @param {GuildMemberResolvable} owner The new owner of the guild
|
* @param {GuildMemberResolvable} owner The new owner of the guild
|
||||||
|
* @param {string} [reason] Reason for setting the new owner
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild owner
|
* // Edit the guild owner
|
||||||
@@ -615,25 +748,28 @@ class Guild {
|
|||||||
* .then(updated => console.log(`Updated the guild owner to ${updated.owner.username}`))
|
* .then(updated => console.log(`Updated the guild owner to ${updated.owner.username}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setOwner(owner) {
|
setOwner(owner, reason) {
|
||||||
return this.edit({ owner });
|
return this.edit({ owner }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a new guild splash screen.
|
* Set a new guild splash screen.
|
||||||
* @param {Base64Resolvable} splash The new splash screen of the guild
|
* @param {BufferResolvable|Base64Resolvable} splash The new splash screen of the guild
|
||||||
|
* @param {string} [reason] Reason for changing the guild's splash screen
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit the guild splash
|
* // Edit the guild splash
|
||||||
* guild.setIcon(fs.readFileSync('./splash.png'))
|
* guild.setSplash('./splash.png')
|
||||||
* .then(updated => console.log('Updated the guild splash'))
|
* .then(updated => console.log('Updated the guild splash'))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setSplash(splash) {
|
setSplash(splash) {
|
||||||
return this.edit({ splash });
|
return this.client.resolver.resolveImage(splash).then(data => this.edit({ splash: data }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Sets the position of the guild in the guild listing.
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @param {number} position Absolute or relative position
|
* @param {number} position Absolute or relative position
|
||||||
* @param {boolean} [relative=false] Whether to position relatively or absolutely
|
* @param {boolean} [relative=false] Whether to position relatively or absolutely
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
@@ -648,7 +784,7 @@ class Guild {
|
|||||||
/**
|
/**
|
||||||
* Marks all messages in this guild as read.
|
* Marks all messages in this guild as read.
|
||||||
* <warn>This is only available when using a user account.</warn>
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @returns {Promise<Guild>} This guild
|
* @returns {Promise<Guild>}
|
||||||
*/
|
*/
|
||||||
acknowledge() {
|
acknowledge() {
|
||||||
return this.client.rest.methods.ackGuild(this);
|
return this.client.rest.methods.ackGuild(this);
|
||||||
@@ -656,6 +792,7 @@ class Guild {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow direct messages from guild members.
|
* Allow direct messages from guild members.
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @param {boolean} allow Whether to allow direct messages
|
* @param {boolean} allow Whether to allow direct messages
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
*/
|
*/
|
||||||
@@ -678,8 +815,8 @@ class Guild {
|
|||||||
* @example
|
* @example
|
||||||
* // Ban a user by ID (or with a user/guild member object)
|
* // Ban a user by ID (or with a user/guild member object)
|
||||||
* guild.ban('some user ID')
|
* guild.ban('some user ID')
|
||||||
* .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`))
|
* .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
ban(user, options = {}) {
|
ban(user, options = {}) {
|
||||||
if (typeof options === 'number') {
|
if (typeof options === 'number') {
|
||||||
@@ -694,21 +831,23 @@ class Guild {
|
|||||||
/**
|
/**
|
||||||
* Unbans a user from the guild.
|
* Unbans a user from the guild.
|
||||||
* @param {UserResolvable} user The user to unban
|
* @param {UserResolvable} user The user to unban
|
||||||
|
* @param {string} [reason] Reason for unbanning the user
|
||||||
* @returns {Promise<User>}
|
* @returns {Promise<User>}
|
||||||
* @example
|
* @example
|
||||||
* // Unban a user by ID (or with a user/guild member object)
|
* // Unban a user by ID (or with a user/guild member object)
|
||||||
* guild.unban('some user ID')
|
* guild.unban('some user ID')
|
||||||
* .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`))
|
* .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
unban(user) {
|
unban(user, reason) {
|
||||||
return this.client.rest.methods.unbanGuildMember(this, user);
|
return this.client.rest.methods.unbanGuildMember(this, user, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prunes members from the guild based on how long they have been inactive.
|
* Prunes members from the guild based on how long they have been inactive.
|
||||||
* @param {number} days Number of days of inactivity required to kick
|
* @param {number} days Number of days of inactivity required to kick
|
||||||
* @param {boolean} [dry=false] If true, will return number of users that will be kicked, without actually doing it
|
* @param {boolean} [dry=false] If true, will return number of users that will be kicked, without actually doing it
|
||||||
|
* @param {string} [reason] Reason for this prune
|
||||||
* @returns {Promise<number>} The number of members that were/will be kicked
|
* @returns {Promise<number>} The number of members that were/will be kicked
|
||||||
* @example
|
* @example
|
||||||
* // See how many members will be pruned
|
* // See how many members will be pruned
|
||||||
@@ -721,9 +860,9 @@ class Guild {
|
|||||||
* .then(pruned => console.log(`I just pruned ${pruned} people!`))
|
* .then(pruned => console.log(`I just pruned ${pruned} people!`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
pruneMembers(days, dry = false) {
|
pruneMembers(days, dry = false, reason) {
|
||||||
if (typeof days !== 'number') throw new TypeError('Days must be a number.');
|
if (typeof days !== 'number') throw new TypeError('Days must be a number.');
|
||||||
return this.client.rest.methods.pruneGuildMembers(this, days, dry);
|
return this.client.rest.methods.pruneGuildMembers(this, days, dry, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -738,16 +877,17 @@ class Guild {
|
|||||||
* Creates a new channel in the guild.
|
* Creates a new channel in the guild.
|
||||||
* @param {string} name The name of the new channel
|
* @param {string} name The name of the new channel
|
||||||
* @param {string} type The type of the new channel, either `text` or `voice`
|
* @param {string} type The type of the new channel, either `text` or `voice`
|
||||||
* @param {Array<PermissionOverwrites|Object>} overwrites Permission overwrites to apply to the new channel
|
* @param {Array<PermissionOverwrites|Object>} [overwrites] Permission overwrites to apply to the new channel
|
||||||
|
* @param {string} [reason] Reason for creating this channel
|
||||||
* @returns {Promise<TextChannel|VoiceChannel>}
|
* @returns {Promise<TextChannel|VoiceChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Create a new text channel
|
* // Create a new text channel
|
||||||
* guild.createChannel('new-general', 'text')
|
* guild.createChannel('new-general', 'text')
|
||||||
* .then(channel => console.log(`Created new channel ${channel}`))
|
* .then(channel => console.log(`Created new channel ${channel}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
createChannel(name, type, overwrites) {
|
createChannel(name, type, overwrites, reason) {
|
||||||
return this.client.rest.methods.createChannel(this, name, type, overwrites);
|
return this.client.rest.methods.createChannel(this, name, type, overwrites, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -763,8 +903,8 @@ class Guild {
|
|||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
* @example
|
* @example
|
||||||
* guild.updateChannels([{ channel: channelID, position: newChannelIndex }])
|
* guild.updateChannels([{ channel: channelID, position: newChannelIndex }])
|
||||||
* .then(guild => console.log(`Updated channel positions for ${guild.id}`))
|
* .then(guild => console.log(`Updated channel positions for ${guild.id}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setChannelPositions(channelPositions) {
|
setChannelPositions(channelPositions) {
|
||||||
return this.client.rest.methods.updateChannelPositions(this.id, channelPositions);
|
return this.client.rest.methods.updateChannelPositions(this.id, channelPositions);
|
||||||
@@ -773,23 +913,24 @@ class Guild {
|
|||||||
/**
|
/**
|
||||||
* Creates a new role in the guild with given information
|
* Creates a new role in the guild with given information
|
||||||
* @param {RoleData} [data] The data to update the role with
|
* @param {RoleData} [data] The data to update the role with
|
||||||
|
* @param {string} [reason] Reason for creating this role
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Create a new role
|
* // Create a new role
|
||||||
* guild.createRole()
|
* guild.createRole()
|
||||||
* .then(role => console.log(`Created role ${role}`))
|
* .then(role => console.log(`Created role ${role}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
* @example
|
* @example
|
||||||
* // Create a new role with data
|
* // Create a new role with data
|
||||||
* guild.createRole({
|
* guild.createRole({
|
||||||
* name: 'Super Cool People',
|
* name: 'Super Cool People',
|
||||||
* color: 'BLUE',
|
* color: 'BLUE',
|
||||||
* })
|
* })
|
||||||
* .then(role => console.log(`Created role ${role}`))
|
* .then(role => console.log(`Created role ${role}`))
|
||||||
* .catch(console.error)
|
* .catch(console.error)
|
||||||
*/
|
*/
|
||||||
createRole(data = {}) {
|
createRole(data = {}, reason) {
|
||||||
return this.client.rest.methods.createGuildRole(this, data);
|
return this.client.rest.methods.createGuildRole(this, data, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -797,39 +938,38 @@ class Guild {
|
|||||||
* @param {BufferResolvable|Base64Resolvable} attachment The image for the emoji
|
* @param {BufferResolvable|Base64Resolvable} attachment The image for the emoji
|
||||||
* @param {string} name The name for the emoji
|
* @param {string} name The name for the emoji
|
||||||
* @param {Collection<Snowflake, Role>|Role[]} [roles] Roles to limit the emoji to
|
* @param {Collection<Snowflake, Role>|Role[]} [roles] Roles to limit the emoji to
|
||||||
|
* @param {string} [reason] Reason for creating the emoji
|
||||||
* @returns {Promise<Emoji>} The created emoji
|
* @returns {Promise<Emoji>} The created emoji
|
||||||
* @example
|
* @example
|
||||||
* // Create a new emoji from a url
|
* // Create a new emoji from a url
|
||||||
* guild.createEmoji('https://i.imgur.com/w3duR07.png', 'rip')
|
* guild.createEmoji('https://i.imgur.com/w3duR07.png', 'rip')
|
||||||
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
|
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
* @example
|
* @example
|
||||||
* // Create a new emoji from a file on your computer
|
* // Create a new emoji from a file on your computer
|
||||||
* guild.createEmoji('./memes/banana.png', 'banana')
|
* guild.createEmoji('./memes/banana.png', 'banana')
|
||||||
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
|
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
createEmoji(attachment, name, roles) {
|
createEmoji(attachment, name, roles, reason) {
|
||||||
return new Promise(resolve => {
|
if (typeof attachment === 'string' && attachment.startsWith('data:')) {
|
||||||
if (typeof attachment === 'string' && attachment.startsWith('data:')) {
|
return this.client.rest.methods.createEmoji(this, attachment, name, roles, reason);
|
||||||
resolve(this.client.rest.methods.createEmoji(this, attachment, name, roles));
|
} else {
|
||||||
} else {
|
return this.client.resolver.resolveImage(attachment).then(data =>
|
||||||
this.client.resolver.resolveBuffer(attachment).then(data => {
|
this.client.rest.methods.createEmoji(this, data, name, roles, reason)
|
||||||
const dataURI = this.client.resolver.resolveBase64(data);
|
);
|
||||||
resolve(this.client.rest.methods.createEmoji(this, dataURI, name, roles));
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete an emoji.
|
* Delete an emoji.
|
||||||
* @param {Emoji|string} emoji The emoji to delete
|
* @param {Emoji|string} emoji The emoji to delete
|
||||||
|
* @param {string} [reason] Reason for deleting the emoji
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
deleteEmoji(emoji) {
|
deleteEmoji(emoji, reason) {
|
||||||
if (!(emoji instanceof Emoji)) emoji = this.emojis.get(emoji);
|
if (!(emoji instanceof Emoji)) emoji = this.emojis.get(emoji);
|
||||||
return this.client.rest.methods.deleteEmoji(emoji);
|
return this.client.rest.methods.deleteEmoji(emoji, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -838,8 +978,8 @@ class Guild {
|
|||||||
* @example
|
* @example
|
||||||
* // Leave a guild
|
* // Leave a guild
|
||||||
* guild.leave()
|
* guild.leave()
|
||||||
* .then(g => console.log(`Left the guild ${g}`))
|
* .then(g => console.log(`Left the guild ${g}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
leave() {
|
leave() {
|
||||||
return this.client.rest.methods.leaveGuild(this);
|
return this.client.rest.methods.leaveGuild(this);
|
||||||
@@ -851,8 +991,8 @@ class Guild {
|
|||||||
* @example
|
* @example
|
||||||
* // Delete a guild
|
* // Delete a guild
|
||||||
* guild.delete()
|
* guild.delete()
|
||||||
* .then(g => console.log(`Deleted the guild ${g}`))
|
* .then(g => console.log(`Deleted the guild ${g}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete() {
|
||||||
return this.client.rest.methods.deleteGuild(this);
|
return this.client.rest.methods.deleteGuild(this);
|
||||||
@@ -1063,10 +1203,22 @@ class Guild {
|
|||||||
_sortPositionWithID(collection) {
|
_sortPositionWithID(collection) {
|
||||||
return collection.sort((a, b) =>
|
return collection.sort((a, b) =>
|
||||||
a.position !== b.position ?
|
a.position !== b.position ?
|
||||||
a.position - b.position :
|
a.position - b.position :
|
||||||
Long.fromString(a.id).sub(Long.fromString(b.id)).toNumber()
|
Long.fromString(a.id).sub(Long.fromString(b.id)).toNumber()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `#general` TextChannel of the guild
|
||||||
|
* @name Guild#defaultChannel
|
||||||
|
* @type {TextChannel}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
Object.defineProperty(Guild.prototype, 'defaultChannel', {
|
||||||
|
get: util.deprecate(function defaultChannel() {
|
||||||
|
return this.channels.get(this.id);
|
||||||
|
}, 'Guild#defaultChannel: This property is obsolete, will be removed in v12.0.0, and may not function as expected.'),
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = Guild;
|
module.exports = Guild;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const Collection = require('../util/Collection');
|
|||||||
const Snowflake = require('../util/Snowflake');
|
const Snowflake = require('../util/Snowflake');
|
||||||
|
|
||||||
const Targets = {
|
const Targets = {
|
||||||
|
ALL: 'ALL',
|
||||||
GUILD: 'GUILD',
|
GUILD: 'GUILD',
|
||||||
CHANNEL: 'CHANNEL',
|
CHANNEL: 'CHANNEL',
|
||||||
USER: 'USER',
|
USER: 'USER',
|
||||||
@@ -9,9 +10,11 @@ const Targets = {
|
|||||||
INVITE: 'INVITE',
|
INVITE: 'INVITE',
|
||||||
WEBHOOK: 'WEBHOOK',
|
WEBHOOK: 'WEBHOOK',
|
||||||
EMOJI: 'EMOJI',
|
EMOJI: 'EMOJI',
|
||||||
|
MESSAGE: 'MESSAGE',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Actions = {
|
const Actions = {
|
||||||
|
ALL: null,
|
||||||
GUILD_UPDATE: 1,
|
GUILD_UPDATE: 1,
|
||||||
CHANNEL_CREATE: 10,
|
CHANNEL_CREATE: 10,
|
||||||
CHANNEL_UPDATE: 11,
|
CHANNEL_UPDATE: 11,
|
||||||
@@ -37,6 +40,7 @@ const Actions = {
|
|||||||
EMOJI_CREATE: 60,
|
EMOJI_CREATE: 60,
|
||||||
EMOJI_UPDATE: 61,
|
EMOJI_UPDATE: 61,
|
||||||
EMOJI_DELETE: 62,
|
EMOJI_DELETE: 62,
|
||||||
|
MESSAGE_DELETE: 72,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -60,13 +64,11 @@ class GuildAuditLogs {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles possible promises for entry targets.
|
* Handles possible promises for entry targets.
|
||||||
* @returns {GuildAuditLogs}
|
* @returns {Promise<GuildAuditLogs>}
|
||||||
*/
|
*/
|
||||||
static build(...args) {
|
static build(...args) {
|
||||||
return new Promise(resolve => {
|
const logs = new GuildAuditLogs(...args);
|
||||||
const logs = new GuildAuditLogs(...args);
|
return Promise.all(logs.entries.map(e => e.target)).then(() => logs);
|
||||||
Promise.all(logs.entries.map(e => e.target)).then(() => resolve(logs));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,6 +84,7 @@ class GuildAuditLogs {
|
|||||||
if (target < 50) return Targets.INVITE;
|
if (target < 50) return Targets.INVITE;
|
||||||
if (target < 60) return Targets.WEBHOOK;
|
if (target < 60) return Targets.WEBHOOK;
|
||||||
if (target < 70) return Targets.EMOJI;
|
if (target < 70) return Targets.EMOJI;
|
||||||
|
if (target < 80) return Targets.MESSAGE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +115,7 @@ class GuildAuditLogs {
|
|||||||
Actions.INVITE_DELETE,
|
Actions.INVITE_DELETE,
|
||||||
Actions.WEBHOOK_DELETE,
|
Actions.WEBHOOK_DELETE,
|
||||||
Actions.EMOJI_DELETE,
|
Actions.EMOJI_DELETE,
|
||||||
|
Actions.MESSAGE_DELETE,
|
||||||
].includes(action)) return 'DELETE';
|
].includes(action)) return 'DELETE';
|
||||||
|
|
||||||
if ([
|
if ([
|
||||||
@@ -119,6 +123,7 @@ class GuildAuditLogs {
|
|||||||
Actions.CHANNEL_UPDATE,
|
Actions.CHANNEL_UPDATE,
|
||||||
Actions.CHANNEL_OVERWRITE_UPDATE,
|
Actions.CHANNEL_OVERWRITE_UPDATE,
|
||||||
Actions.MEMBER_UPDATE,
|
Actions.MEMBER_UPDATE,
|
||||||
|
Actions.MEMBER_ROLE_UPDATE,
|
||||||
Actions.ROLE_UPDATE,
|
Actions.ROLE_UPDATE,
|
||||||
Actions.INVITE_UPDATE,
|
Actions.INVITE_UPDATE,
|
||||||
Actions.WEBHOOK_UPDATE,
|
Actions.WEBHOOK_UPDATE,
|
||||||
@@ -166,10 +171,18 @@ class GuildAuditLogsEntry {
|
|||||||
this.executor = guild.client.users.get(data.user_id);
|
this.executor = guild.client.users.get(data.user_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specific property changes
|
* An entry in the audit log representing a specific change.
|
||||||
* @type {Object[]}
|
* @typedef {object} AuditLogChange
|
||||||
|
* @property {string} key The property that was changed, e.g. `nick` for nickname changes
|
||||||
|
* @property {*} [old] The old value of the change, e.g. for nicknames, the old nickname
|
||||||
|
* @property {*} [new] The new value of the change, e.g. for nicknames, the new nickname
|
||||||
*/
|
*/
|
||||||
this.changes = data.changes ? data.changes.map(c => ({ name: c.key, old: c.old_value, new: c.new_value })) : null;
|
|
||||||
|
/**
|
||||||
|
* Specific property changes
|
||||||
|
* @type {AuditLogChange[]}
|
||||||
|
*/
|
||||||
|
this.changes = data.changes ? data.changes.map(c => ({ key: c.key, old: c.old_value, new: c.new_value })) : null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of this entry
|
* The ID of this entry
|
||||||
@@ -188,15 +201,20 @@ class GuildAuditLogsEntry {
|
|||||||
removed: data.options.members_removed,
|
removed: data.options.members_removed,
|
||||||
days: data.options.delete_member_days,
|
days: data.options.delete_member_days,
|
||||||
};
|
};
|
||||||
|
} else if (data.action_type === Actions.MESSAGE_DELETE) {
|
||||||
|
this.extra = {
|
||||||
|
count: data.options.count,
|
||||||
|
channel: guild.channels.get(data.options.channel_id),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
switch (data.options.type) {
|
switch (data.options.type) {
|
||||||
case 'member':
|
case 'member':
|
||||||
this.extra = guild.members.get(this.options.id);
|
this.extra = guild.members.get(data.options.id);
|
||||||
if (!this.extra) this.extra = { id: this.options.id };
|
if (!this.extra) this.extra = { id: data.options.id };
|
||||||
break;
|
break;
|
||||||
case 'role':
|
case 'role':
|
||||||
this.extra = guild.roles.get(this.options.id);
|
this.extra = guild.roles.get(data.options.id);
|
||||||
if (!this.extra) this.extra = { id: this.options.id, name: this.options.role_name };
|
if (!this.extra) this.extra = { id: data.options.id, name: data.options.role_name };
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -217,12 +235,14 @@ class GuildAuditLogsEntry {
|
|||||||
return this.target;
|
return this.target;
|
||||||
});
|
});
|
||||||
} else if (targetType === Targets.INVITE) {
|
} else if (targetType === Targets.INVITE) {
|
||||||
const change = this.changes.find(c => c.name === 'code');
|
const change = this.changes.find(c => c.key === 'code');
|
||||||
this.target = guild.fetchInvites()
|
this.target = guild.fetchInvites()
|
||||||
.then(invites => {
|
.then(invites => {
|
||||||
this.target = invites.find(i => i.code === (change.new || change.old));
|
this.target = invites.find(i => i.code === (change.new_value || change.old_value));
|
||||||
return this.target;
|
return this.target;
|
||||||
});
|
});
|
||||||
|
} else if (targetType === Targets.MESSAGE) {
|
||||||
|
this.target = guild.client.users.get(data.target_id);
|
||||||
} else {
|
} else {
|
||||||
this.target = guild[`${targetType.toLowerCase()}s`].get(data.target_id);
|
this.target = guild[`${targetType.toLowerCase()}s`].get(data.target_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const Role = require('./Role');
|
|||||||
const PermissionOverwrites = require('./PermissionOverwrites');
|
const PermissionOverwrites = require('./PermissionOverwrites');
|
||||||
const Permissions = require('../util/Permissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
|
const Constants = require('../util/Constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a guild channel (i.e. text channels and voice channels).
|
* Represents a guild channel (i.e. text channels and voice channels).
|
||||||
@@ -72,6 +73,9 @@ class GuildChannel extends Channel {
|
|||||||
const roles = member.roles;
|
const roles = member.roles;
|
||||||
for (const role of roles.values()) permissions |= role.permissions;
|
for (const role of roles.values()) permissions |= role.permissions;
|
||||||
|
|
||||||
|
const admin = Boolean(permissions & Permissions.FLAGS.ADMINISTRATOR);
|
||||||
|
if (admin) return new Permissions(Permissions.ALL);
|
||||||
|
|
||||||
const overwrites = this.overwritesFor(member, true, roles);
|
const overwrites = this.overwritesFor(member, true, roles);
|
||||||
|
|
||||||
if (overwrites.everyone) {
|
if (overwrites.everyone) {
|
||||||
@@ -91,9 +95,6 @@ class GuildChannel extends Channel {
|
|||||||
permissions |= overwrites.member.allow;
|
permissions |= overwrites.member.allow;
|
||||||
}
|
}
|
||||||
|
|
||||||
const admin = Boolean(permissions & Permissions.FLAGS.ADMINISTRATOR);
|
|
||||||
if (admin) permissions = Permissions.ALL;
|
|
||||||
|
|
||||||
return new Permissions(member, permissions);
|
return new Permissions(member, permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,18 +137,19 @@ class GuildChannel extends Channel {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Overwrites the permissions for a user or role in this channel.
|
* Overwrites the permissions for a user or role in this channel.
|
||||||
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
|
* @param {Role|Snowflake|UserResolvable} userOrRole The user or role to update
|
||||||
* @param {PermissionOverwriteOptions} options The configuration for the update
|
* @param {PermissionOverwriteOptions} options The configuration for the update
|
||||||
|
* @param {string} [reason] Reason for creating/editing this overwrite
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
* @example
|
* @example
|
||||||
* // Overwrite permissions for a message author
|
* // Overwrite permissions for a message author
|
||||||
* message.channel.overwritePermissions(message.author, {
|
* message.channel.overwritePermissions(message.author, {
|
||||||
* SEND_MESSAGES: false
|
* SEND_MESSAGES: false
|
||||||
* })
|
* })
|
||||||
* .then(() => console.log('Done!'))
|
* .then(() => console.log('Done!'))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
overwritePermissions(userOrRole, options) {
|
overwritePermissions(userOrRole, options, reason) {
|
||||||
const payload = {
|
const payload = {
|
||||||
allow: 0,
|
allow: 0,
|
||||||
deny: 0,
|
deny: 0,
|
||||||
@@ -186,7 +188,7 @@ class GuildChannel extends Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.client.rest.methods.setChannelOverwrite(this, payload);
|
return this.client.rest.methods.setChannelOverwrite(this, payload, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -202,29 +204,31 @@ class GuildChannel extends Channel {
|
|||||||
/**
|
/**
|
||||||
* Edits the channel.
|
* Edits the channel.
|
||||||
* @param {ChannelData} data The new data for the channel
|
* @param {ChannelData} data The new data for the channel
|
||||||
|
* @param {string} [reason] Reason for editing this channel
|
||||||
* @returns {Promise<GuildChannel>}
|
* @returns {Promise<GuildChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit a channel
|
* // Edit a channel
|
||||||
* channel.edit({name: 'new-channel'})
|
* channel.edit({name: 'new-channel'})
|
||||||
* .then(c => console.log(`Edited channel ${c}`))
|
* .then(c => console.log(`Edited channel ${c}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
edit(data) {
|
edit(data, reason) {
|
||||||
return this.client.rest.methods.updateChannel(this, data);
|
return this.client.rest.methods.updateChannel(this, data, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a new name for the guild channel.
|
* Set a new name for the guild channel.
|
||||||
* @param {string} name The new name for the guild channel
|
* @param {string} name The new name for the guild channel
|
||||||
|
* @param {string} [reason] Reason for changing the guild channel's name
|
||||||
* @returns {Promise<GuildChannel>}
|
* @returns {Promise<GuildChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set a new channel name
|
* // Set a new channel name
|
||||||
* channel.setName('not_general')
|
* channel.setName('not_general')
|
||||||
* .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))
|
* .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setName(name) {
|
setName(name, reason) {
|
||||||
return this.edit({ name });
|
return this.edit({ name }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,8 +239,8 @@ class GuildChannel extends Channel {
|
|||||||
* @example
|
* @example
|
||||||
* // Set a new channel position
|
* // Set a new channel position
|
||||||
* channel.setPosition(2)
|
* channel.setPosition(2)
|
||||||
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setPosition(position, relative) {
|
setPosition(position, relative) {
|
||||||
return this.guild.setChannelPosition(this, position, relative).then(() => this);
|
return this.guild.setChannelPosition(this, position, relative).then(() => this);
|
||||||
@@ -245,34 +249,32 @@ class GuildChannel extends Channel {
|
|||||||
/**
|
/**
|
||||||
* Set a new topic for the guild channel.
|
* Set a new topic for the guild channel.
|
||||||
* @param {string} topic The new topic for the guild channel
|
* @param {string} topic The new topic for the guild channel
|
||||||
|
* @param {string} [reason] Reason for changing the guild channel's topic
|
||||||
* @returns {Promise<GuildChannel>}
|
* @returns {Promise<GuildChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set a new channel topic
|
* // Set a new channel topic
|
||||||
* channel.setTopic('needs more rate limiting')
|
* channel.setTopic('needs more rate limiting')
|
||||||
* .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
|
* .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setTopic(topic) {
|
setTopic(topic, reason) {
|
||||||
return this.client.rest.methods.updateChannel(this, { topic });
|
return this.edit({ topic }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Options given when creating a guild channel invite.
|
|
||||||
* @typedef {Object} InviteOptions
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an invite to this guild channel.
|
* Create an invite to this guild channel.
|
||||||
* @param {InviteOptions} [options={}] Options for the invite
|
* <warn>This is only available when using a bot account.</warn>
|
||||||
|
* @param {Object} [options={}] Options for the invite
|
||||||
* @param {boolean} [options.temporary=false] Whether members that joined via the invite should be automatically
|
* @param {boolean} [options.temporary=false] Whether members that joined via the invite should be automatically
|
||||||
* kicked after 24 hours if they have not yet received a role
|
* kicked after 24 hours if they have not yet received a role
|
||||||
* @param {number} [options.maxAge=86400] How long the invite should last (in seconds, 0 for forever)
|
* @param {number} [options.maxAge=86400] How long the invite should last (in seconds, 0 for forever)
|
||||||
* @param {number} [options.maxUses=0] Maximum number of uses
|
* @param {number} [options.maxUses=0] Maximum number of uses
|
||||||
|
* @param {boolean} [options.unique=false] Create a unique invite, or use an existing one with similar settings
|
||||||
|
* @param {string} [reason] Reason for creating the invite
|
||||||
* @returns {Promise<Invite>}
|
* @returns {Promise<Invite>}
|
||||||
*/
|
*/
|
||||||
createInvite(options = {}) {
|
createInvite(options = {}, reason) {
|
||||||
return this.client.rest.methods.createChannelInvite(this, options);
|
return this.client.rest.methods.createChannelInvite(this, options, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -280,13 +282,28 @@ class GuildChannel extends Channel {
|
|||||||
* @param {string} [name=this.name] Optional name for the new channel, otherwise it has the name of this channel
|
* @param {string} [name=this.name] Optional name for the new channel, otherwise it has the name of this channel
|
||||||
* @param {boolean} [withPermissions=true] Whether to clone the channel with this channel's permission overwrites
|
* @param {boolean} [withPermissions=true] Whether to clone the channel with this channel's permission overwrites
|
||||||
* @param {boolean} [withTopic=true] Whether to clone the channel with this channel's topic
|
* @param {boolean} [withTopic=true] Whether to clone the channel with this channel's topic
|
||||||
|
* @param {string} [reason] Reason for cloning this channel
|
||||||
* @returns {Promise<GuildChannel>}
|
* @returns {Promise<GuildChannel>}
|
||||||
*/
|
*/
|
||||||
clone(name = this.name, withPermissions = true, withTopic = true) {
|
clone(name = this.name, withPermissions = true, withTopic = true, reason) {
|
||||||
return this.guild.createChannel(name, this.type, withPermissions ? this.permissionOverwrites : [])
|
return this.guild.createChannel(name, this.type, withPermissions ? this.permissionOverwrites : [], reason)
|
||||||
.then(channel => withTopic ? channel.setTopic(this.topic) : channel);
|
.then(channel => withTopic ? channel.setTopic(this.topic) : channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this channel.
|
||||||
|
* @param {string} [reason] Reason for deleting this channel
|
||||||
|
* @returns {Promise<GuildChannel>}
|
||||||
|
* @example
|
||||||
|
* // Delete the channel
|
||||||
|
* channel.delete('making room for new channels')
|
||||||
|
* .then(channel => console.log(`Deleted ${channel.name} to make room for new channels`))
|
||||||
|
* .catch(console.error); // Log error
|
||||||
|
*/
|
||||||
|
delete(reason) {
|
||||||
|
return this.client.rest.methods.deleteChannel(this, reason);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this channel has the same type, topic, position, name, overwrites and ID as another channel.
|
* Checks if this channel has the same type, topic, position, name, overwrites and ID as another channel.
|
||||||
* In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.
|
* In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.
|
||||||
@@ -322,6 +339,36 @@ class GuildChannel extends Channel {
|
|||||||
this.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS);
|
this.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the channel is muted
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
|
* @type {?boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get muted() {
|
||||||
|
if (this.client.user.bot) return null;
|
||||||
|
try {
|
||||||
|
return this.client.user.guildSettings.get(this.guild.id).channelOverrides.get(this.id).muted;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of message that should notify you
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
|
* @type {?MessageNotificationType}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get messageNotifications() {
|
||||||
|
if (this.client.user.bot) return null;
|
||||||
|
try {
|
||||||
|
return this.client.user.guildSettings.get(this.guild.id).channelOverrides.get(this.id).messageNotifications;
|
||||||
|
} catch (err) {
|
||||||
|
return Constants.MessageNotificationTypes[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
|
* When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
|
|||||||
@@ -345,28 +345,31 @@ class GuildMember {
|
|||||||
/**
|
/**
|
||||||
* Edit a guild member.
|
* Edit a guild member.
|
||||||
* @param {GuildMemberEditData} data The data to edit the member with
|
* @param {GuildMemberEditData} data The data to edit the member with
|
||||||
|
* @param {string} [reason] Reason for editing this user
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
edit(data) {
|
edit(data, reason) {
|
||||||
return this.client.rest.methods.updateGuildMember(this, data);
|
return this.client.rest.methods.updateGuildMember(this, data, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mute/unmute a user.
|
* Mute/unmute a user.
|
||||||
* @param {boolean} mute Whether or not the member should be muted
|
* @param {boolean} mute Whether or not the member should be muted
|
||||||
|
* @param {string} [reason] Reason for muting or unmuting
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
setMute(mute) {
|
setMute(mute, reason) {
|
||||||
return this.edit({ mute });
|
return this.edit({ mute }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deafen/undeafen a user.
|
* Deafen/undeafen a user.
|
||||||
* @param {boolean} deaf Whether or not the member should be deafened
|
* @param {boolean} deaf Whether or not the member should be deafened
|
||||||
|
* @param {string} [reason] Reason for deafening or undeafening
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
setDeaf(deaf) {
|
setDeaf(deaf, reason) {
|
||||||
return this.edit({ deaf });
|
return this.edit({ deaf }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -381,29 +384,32 @@ class GuildMember {
|
|||||||
/**
|
/**
|
||||||
* Sets the roles applied to the member.
|
* Sets the roles applied to the member.
|
||||||
* @param {Collection<Snowflake, Role>|Role[]|Snowflake[]} roles The roles or role IDs to apply
|
* @param {Collection<Snowflake, Role>|Role[]|Snowflake[]} roles The roles or role IDs to apply
|
||||||
|
* @param {string} [reason] Reason for applying the roles
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
setRoles(roles) {
|
setRoles(roles, reason) {
|
||||||
return this.edit({ roles });
|
return this.edit({ roles }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a single role to the member.
|
* Adds a single role to the member.
|
||||||
* @param {Role|Snowflake} role The role or ID of the role to add
|
* @param {Role|Snowflake} role The role or ID of the role to add
|
||||||
|
* @param {string} [reason] Reason for adding the role
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
addRole(role) {
|
addRole(role, reason) {
|
||||||
if (!(role instanceof Role)) role = this.guild.roles.get(role);
|
if (!(role instanceof Role)) role = this.guild.roles.get(role);
|
||||||
if (!role) throw new TypeError('Supplied parameter was neither a Role nor a Snowflake.');
|
if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.'));
|
||||||
return this.client.rest.methods.addMemberRole(this, role);
|
return this.client.rest.methods.addMemberRole(this, role, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds multiple roles to the member.
|
* Adds multiple roles to the member.
|
||||||
* @param {Collection<Snowflake, Role>|Role[]|Snowflake[]} roles The roles or role IDs to add
|
* @param {Collection<Snowflake, Role>|Role[]|Snowflake[]} roles The roles or role IDs to add
|
||||||
|
* @param {string} [reason] Reason for adding the roles
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
addRoles(roles) {
|
addRoles(roles, reason) {
|
||||||
let allRoles;
|
let allRoles;
|
||||||
if (roles instanceof Collection) {
|
if (roles instanceof Collection) {
|
||||||
allRoles = this._roles.slice();
|
allRoles = this._roles.slice();
|
||||||
@@ -411,26 +417,28 @@ class GuildMember {
|
|||||||
} else {
|
} else {
|
||||||
allRoles = this._roles.concat(roles);
|
allRoles = this._roles.concat(roles);
|
||||||
}
|
}
|
||||||
return this.edit({ roles: allRoles });
|
return this.edit({ roles: allRoles }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a single role from the member.
|
* Removes a single role from the member.
|
||||||
* @param {Role|Snowflake} role The role or ID of the role to remove
|
* @param {Role|Snowflake} role The role or ID of the role to remove
|
||||||
|
* @param {string} [reason] Reason for removing the role
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
removeRole(role) {
|
removeRole(role, reason) {
|
||||||
if (!(role instanceof Role)) role = this.guild.roles.get(role);
|
if (!(role instanceof Role)) role = this.guild.roles.get(role);
|
||||||
if (!role) throw new TypeError('Supplied parameter was neither a Role nor a Snowflake.');
|
if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.'));
|
||||||
return this.client.rest.methods.removeMemberRole(this, role);
|
return this.client.rest.methods.removeMemberRole(this, role, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes multiple roles from the member.
|
* Removes multiple roles from the member.
|
||||||
* @param {Collection<Snowflake, Role>|Role[]|Snowflake[]} roles The roles or role IDs to remove
|
* @param {Collection<Snowflake, Role>|Role[]|Snowflake[]} roles The roles or role IDs to remove
|
||||||
|
* @param {string} [reason] Reason for removing the roles
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
removeRoles(roles) {
|
removeRoles(roles, reason) {
|
||||||
const allRoles = this._roles.slice();
|
const allRoles = this._roles.slice();
|
||||||
if (roles instanceof Collection) {
|
if (roles instanceof Collection) {
|
||||||
for (const role of roles.values()) {
|
for (const role of roles.values()) {
|
||||||
@@ -443,16 +451,17 @@ class GuildMember {
|
|||||||
if (index >= 0) allRoles.splice(index, 1);
|
if (index >= 0) allRoles.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.edit({ roles: allRoles });
|
return this.edit({ roles: allRoles }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the nickname for the guild member.
|
* Set the nickname for the guild member.
|
||||||
* @param {string} nick The nickname for the guild member
|
* @param {string} nick The nickname for the guild member
|
||||||
|
* @param {string} [reason] Reason for setting the nickname
|
||||||
* @returns {Promise<GuildMember>}
|
* @returns {Promise<GuildMember>}
|
||||||
*/
|
*/
|
||||||
setNickname(nick) {
|
setNickname(nick, reason) {
|
||||||
return this.edit({ nick });
|
return this.edit({ nick }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -481,7 +490,7 @@ class GuildMember {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ban this guild member
|
* Ban this guild member.
|
||||||
* @param {Object|number|string} [options] Ban options. If a number, the number of days to delete messages for, if a
|
* @param {Object|number|string} [options] Ban options. If a number, the number of days to delete messages for, if a
|
||||||
* string, the ban reason. Supplying an object allows you to do both.
|
* string, the ban reason. Supplying an object allows you to do both.
|
||||||
* @param {number} [options.days=0] Number of days of messages to delete
|
* @param {number} [options.days=0] Number of days of messages to delete
|
||||||
|
|||||||
@@ -2,27 +2,6 @@ const PartialGuild = require('./PartialGuild');
|
|||||||
const PartialGuildChannel = require('./PartialGuildChannel');
|
const PartialGuildChannel = require('./PartialGuildChannel');
|
||||||
const Constants = require('../util/Constants');
|
const Constants = require('../util/Constants');
|
||||||
|
|
||||||
/*
|
|
||||||
{ max_age: 86400,
|
|
||||||
code: 'CG9A5',
|
|
||||||
guild:
|
|
||||||
{ splash: null,
|
|
||||||
id: '123123123',
|
|
||||||
icon: '123123123',
|
|
||||||
name: 'name' },
|
|
||||||
created_at: '2016-08-28T19:07:04.763368+00:00',
|
|
||||||
temporary: false,
|
|
||||||
uses: 0,
|
|
||||||
max_uses: 0,
|
|
||||||
inviter:
|
|
||||||
{ username: '123',
|
|
||||||
discriminator: '4204',
|
|
||||||
bot: true,
|
|
||||||
id: '123123123',
|
|
||||||
avatar: '123123123' },
|
|
||||||
channel: { type: 0, id: '123123', name: 'heavy-testing' } }
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an invitation to a guild channel.
|
* Represents an invitation to a guild channel.
|
||||||
* <warn>The only guaranteed properties are `code`, `guild` and `channel`. Other properties can be missing.</warn>
|
* <warn>The only guaranteed properties are `code`, `guild` and `channel`. Other properties can be missing.</warn>
|
||||||
@@ -54,6 +33,30 @@ class Invite {
|
|||||||
*/
|
*/
|
||||||
this.code = data.code;
|
this.code = data.code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The approximate number of online members of the guild this invite is for
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.presenceCount = data.approximate_presence_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The approximate total number of members of the guild this invite is for
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.memberCount = data.approximate_member_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of text channels the guild this invite goes to has
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.textChannelCount = data.guild.text_channel_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of voice channels the guild this invite goes to has
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.voiceChannelCount = data.guild.voice_channel_count;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not this invite is temporary
|
* Whether or not this invite is temporary
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -138,10 +141,11 @@ class Invite {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes this invite.
|
* Deletes this invite.
|
||||||
|
* @param {string} [reason] Reason for deleting this invite
|
||||||
* @returns {Promise<Invite>}
|
* @returns {Promise<Invite>}
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete(reason) {
|
||||||
return this.client.rest.methods.deleteInvite(this);
|
return this.client.rest.methods.deleteInvite(this, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const Mentions = require('./MessageMentions');
|
const Mentions = require('./MessageMentions');
|
||||||
const Attachment = require('./MessageAttachment');
|
const Attachment = require('./MessageAttachment');
|
||||||
const Embed = require('./MessageEmbed');
|
const Embed = require('./MessageEmbed');
|
||||||
|
const RichEmbed = require('./RichEmbed');
|
||||||
const MessageReaction = require('./MessageReaction');
|
const MessageReaction = require('./MessageReaction');
|
||||||
const ReactionCollector = require('./ReactionCollector');
|
const ReactionCollector = require('./ReactionCollector');
|
||||||
const Util = require('../util/Util');
|
const Util = require('../util/Util');
|
||||||
@@ -33,7 +34,7 @@ class Message {
|
|||||||
|
|
||||||
setup(data) { // eslint-disable-line complexity
|
setup(data) { // eslint-disable-line complexity
|
||||||
/**
|
/**
|
||||||
* The ID of the message (unique in the channel it was sent)
|
* The ID of the message
|
||||||
* @type {Snowflake}
|
* @type {Snowflake}
|
||||||
*/
|
*/
|
||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
@@ -57,8 +58,8 @@ class Message {
|
|||||||
this.author = this.client.dataManager.newUser(data.author);
|
this.author = this.client.dataManager.newUser(data.author);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the author of the message as a guild member. Only available if the message comes from a guild
|
* Represents the author of the message as a guild member
|
||||||
* where the author is still a member.
|
* Only available if the message comes from a guild where the author is still a member
|
||||||
* @type {?GuildMember}
|
* @type {?GuildMember}
|
||||||
*/
|
*/
|
||||||
this.member = this.guild ? this.guild.member(this.author) || null : null;
|
this.member = this.guild ? this.guild.member(this.author) || null : null;
|
||||||
@@ -209,8 +210,8 @@ class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message contents with all mentions replaced by the equivalent text. If mentions cannot be resolved to a name,
|
* The message contents with all mentions replaced by the equivalent text.
|
||||||
* the relevant mention in the message content will not be converted
|
* If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted.
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
@@ -254,8 +255,8 @@ class Message {
|
|||||||
* @example
|
* @example
|
||||||
* // Create a reaction collector
|
* // Create a reaction collector
|
||||||
* const collector = message.createReactionCollector(
|
* const collector = message.createReactionCollector(
|
||||||
* (reaction, user) => reaction.emoji.id === '👌' && user.id === 'someID',
|
* (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someID',
|
||||||
* { time: 15000 }
|
* { time: 15000 }
|
||||||
* );
|
* );
|
||||||
* collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
|
* collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
|
||||||
* collector.on('end', collected => console.log(`Collected ${collected.size} items`));
|
* collector.on('end', collected => console.log(`Collected ${collected.size} items`));
|
||||||
@@ -271,8 +272,8 @@ class Message {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to createCollector but in promise form. Resolves with a collection of reactions that pass the specified
|
* Similar to createMessageCollector but in promise form.
|
||||||
* filter.
|
* Resolves with a collection of reactions that pass the specified filter.
|
||||||
* @param {CollectorFilter} filter The filter function to use
|
* @param {CollectorFilter} filter The filter function to use
|
||||||
* @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
|
* @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
|
||||||
* @returns {Promise<Collection<string, MessageReaction>>}
|
* @returns {Promise<Collection<string, MessageReaction>>}
|
||||||
@@ -365,13 +366,13 @@ class Message {
|
|||||||
/**
|
/**
|
||||||
* Edit the content of the message.
|
* Edit the content of the message.
|
||||||
* @param {StringResolvable} [content] The new content for the message
|
* @param {StringResolvable} [content] The new content for the message
|
||||||
* @param {MessageEditOptions} [options] The options to provide
|
* @param {MessageEditOptions|RichEmbed} [options] The options to provide
|
||||||
* @returns {Promise<Message>}
|
* @returns {Promise<Message>}
|
||||||
* @example
|
* @example
|
||||||
* // Update the content of a message
|
* // Update the content of a message
|
||||||
* message.edit('This is my new content!')
|
* message.edit('This is my new content!')
|
||||||
* .then(msg => console.log(`Updated the content of a message from ${msg.author}`))
|
* .then(msg => console.log(`Updated the content of a message from ${msg.author}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
edit(content, options) {
|
edit(content, options) {
|
||||||
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||||
@@ -380,6 +381,7 @@ class Message {
|
|||||||
} else if (!options) {
|
} else if (!options) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
if (options instanceof RichEmbed) options = { embed: options };
|
||||||
return this.client.rest.methods.updateMessage(this, content, options);
|
return this.client.rest.methods.updateMessage(this, content, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,6 +390,7 @@ class Message {
|
|||||||
* @param {string} lang The language for the code block
|
* @param {string} lang The language for the code block
|
||||||
* @param {StringResolvable} content The new content for the message
|
* @param {StringResolvable} content The new content for the message
|
||||||
* @returns {Promise<Message>}
|
* @returns {Promise<Message>}
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
editCode(lang, content) {
|
editCode(lang, content) {
|
||||||
content = Util.escapeMarkdown(this.client.resolver.resolveString(content), true);
|
content = Util.escapeMarkdown(this.client.resolver.resolveString(content), true);
|
||||||
@@ -437,8 +440,8 @@ class Message {
|
|||||||
* @example
|
* @example
|
||||||
* // Delete a message
|
* // Delete a message
|
||||||
* message.delete()
|
* message.delete()
|
||||||
* .then(msg => console.log(`Deleted message from ${msg.author}`))
|
* .then(msg => console.log(`Deleted message from ${msg.author}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
delete(timeout = 0) {
|
delete(timeout = 0) {
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
@@ -460,8 +463,8 @@ class 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!')
|
||||||
* .then(msg => console.log(`Sent a reply to ${msg.author}`))
|
* .then(msg => console.log(`Sent a reply to ${msg.author}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
reply(content, options) {
|
reply(content, options) {
|
||||||
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||||
@@ -533,7 +536,7 @@ class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_addReaction(emoji, user) {
|
_addReaction(emoji, user) {
|
||||||
const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name);
|
const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : emoji.name;
|
||||||
let reaction;
|
let reaction;
|
||||||
if (this.reactions.has(emojiID)) {
|
if (this.reactions.has(emojiID)) {
|
||||||
reaction = this.reactions.get(emojiID);
|
reaction = this.reactions.get(emojiID);
|
||||||
@@ -542,13 +545,15 @@ class Message {
|
|||||||
reaction = new MessageReaction(this, emoji, 0, user.id === this.client.user.id);
|
reaction = new MessageReaction(this, emoji, 0, user.id === this.client.user.id);
|
||||||
this.reactions.set(emojiID, reaction);
|
this.reactions.set(emojiID, reaction);
|
||||||
}
|
}
|
||||||
if (!reaction.users.has(user.id)) reaction.users.set(user.id, user);
|
if (!reaction.users.has(user.id)) {
|
||||||
reaction.count++;
|
reaction.users.set(user.id, user);
|
||||||
|
reaction.count++;
|
||||||
|
}
|
||||||
return reaction;
|
return reaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
_removeReaction(emoji, user) {
|
_removeReaction(emoji, user) {
|
||||||
const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name);
|
const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : emoji.name;
|
||||||
if (this.reactions.has(emojiID)) {
|
if (this.reactions.has(emojiID)) {
|
||||||
const reaction = this.reactions.get(emojiID);
|
const reaction = this.reactions.get(emojiID);
|
||||||
if (reaction.users.has(user.id)) {
|
if (reaction.users.has(user.id)) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const util = require('util');
|
|||||||
* @extends {Collector}
|
* @extends {Collector}
|
||||||
*/
|
*/
|
||||||
class MessageCollector extends Collector {
|
class MessageCollector extends Collector {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TextChannel|DMChannel|GroupDMChannel} channel The channel
|
* @param {TextChannel|DMChannel|GroupDMChannel} channel The channel
|
||||||
* @param {CollectorFilter} filter The filter to be applied to this collector
|
* @param {CollectorFilter} filter The filter to be applied to this collector
|
||||||
@@ -23,7 +22,8 @@ class MessageCollector extends Collector {
|
|||||||
super(channel.client, filter, options);
|
super(channel.client, filter, options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {TextBasedChannel} channel The channel
|
* The channel
|
||||||
|
* @type {TextBasedChannel}
|
||||||
*/
|
*/
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ class MessageCollector extends Collector {
|
|||||||
/**
|
/**
|
||||||
* Handle an incoming message for possible collection.
|
* Handle an incoming message for possible collection.
|
||||||
* @param {Message} message The message that could be collected
|
* @param {Message} message The message that could be collected
|
||||||
* @returns {?{key: Snowflake, value: Message}} Message data to collect
|
* @returns {?{key: Snowflake, value: Message}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handle(message) {
|
handle(message) {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class MessageMentions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Any channels that were mentioned
|
* Any channels that were mentioned
|
||||||
* @type {?Collection<Snowflake, GuildChannel>}
|
* @type {Collection<Snowflake, GuildChannel>}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get channels() {
|
get channels() {
|
||||||
@@ -124,7 +124,7 @@ class MessageMentions {
|
|||||||
MessageMentions.EVERYONE_PATTERN = /@(everyone|here)/g;
|
MessageMentions.EVERYONE_PATTERN = /@(everyone|here)/g;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regular expression that globally matches user mentions like `<#81440962496172032>`
|
* Regular expression that globally matches user mentions like `<@81440962496172032>`
|
||||||
* @type {RegExp}
|
* @type {RegExp}
|
||||||
*/
|
*/
|
||||||
MessageMentions.USERS_PATTERN = /<@!?[0-9]+>/g;
|
MessageMentions.USERS_PATTERN = /<@!?[0-9]+>/g;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class OAuth2Application {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The app's icon hash
|
* The app's icon hash
|
||||||
* @type {string}
|
* @type {?string}
|
||||||
*/
|
*/
|
||||||
this.icon = data.icon;
|
this.icon = data.icon;
|
||||||
|
|
||||||
@@ -124,6 +124,7 @@ class OAuth2Application {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the app's secret and bot token.
|
* Reset the app's secret and bot token.
|
||||||
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @returns {OAuth2Application}
|
* @returns {OAuth2Application}
|
||||||
*/
|
*/
|
||||||
reset() {
|
reset() {
|
||||||
|
|||||||
@@ -33,10 +33,11 @@ class PermissionOverwrites {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete this Permission Overwrite.
|
* Delete this Permission Overwrite.
|
||||||
|
* @param {string} [reason] Reason for deleting this overwrite
|
||||||
* @returns {Promise<PermissionOverwrites>}
|
* @returns {Promise<PermissionOverwrites>}
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete(reason) {
|
||||||
return this.channel.client.rest.methods.deletePermissionOverwrites(this);
|
return this.channel.client.rest.methods.deletePermissionOverwrites(this, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const Collection = require('../util/Collection');
|
|||||||
* @extends {Collector}
|
* @extends {Collector}
|
||||||
*/
|
*/
|
||||||
class ReactionCollector extends Collector {
|
class ReactionCollector extends Collector {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message The message upon which to collect reactions
|
* @param {Message} message The message upon which to collect reactions
|
||||||
* @param {CollectorFilter} filter The filter to apply to this collector
|
* @param {CollectorFilter} filter The filter to apply to this collector
|
||||||
@@ -46,7 +45,7 @@ class ReactionCollector extends Collector {
|
|||||||
/**
|
/**
|
||||||
* Handle an incoming reaction for possible collection.
|
* Handle an incoming reaction for possible collection.
|
||||||
* @param {MessageReaction} reaction The reaction to possibly collect
|
* @param {MessageReaction} reaction The reaction to possibly collect
|
||||||
* @returns {?{key: Snowflake, value: MessageReaction}} Reaction data to collect
|
* @returns {?{key: Snowflake, value: MessageReaction}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handle(reaction) {
|
handle(reaction) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class ReactionEmoji {
|
|||||||
* Creates the text required to form a graphical emoji on Discord.
|
* Creates the text required to form a graphical emoji on Discord.
|
||||||
* @example
|
* @example
|
||||||
* // Send the emoji used in a reaction to the channel the reaction is part of
|
* // Send the emoji used in a reaction to the channel the reaction is part of
|
||||||
* reaction.message.channel.sendMessage(`The emoji used is ${reaction.emoji}`);
|
* reaction.message.channel.send(`The emoji used is ${reaction.emoji}`);
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
toString() {
|
toString() {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const ClientDataResolver = require('../client/ClientDataResolver');
|
const Attachment = require('./Attachment');
|
||||||
|
let ClientDataResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A rich embed to be sent with a message with a fluent interface for creation.
|
* A rich embed to be sent with a message with a fluent interface for creation.
|
||||||
@@ -68,7 +69,7 @@ class RichEmbed {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* File to upload alongside this Embed
|
* File to upload alongside this Embed
|
||||||
* @type {string}
|
* @type {FileOptions|string|Attachment}
|
||||||
*/
|
*/
|
||||||
this.file = data.file;
|
this.file = data.file;
|
||||||
}
|
}
|
||||||
@@ -113,6 +114,7 @@ class RichEmbed {
|
|||||||
* @returns {RichEmbed} This embed
|
* @returns {RichEmbed} This embed
|
||||||
*/
|
*/
|
||||||
setColor(color) {
|
setColor(color) {
|
||||||
|
if (!ClientDataResolver) ClientDataResolver = require('../client/ClientDataResolver');
|
||||||
this.color = ClientDataResolver.resolveColor(color);
|
this.color = ClientDataResolver.resolveColor(color);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -203,11 +205,13 @@ class RichEmbed {
|
|||||||
/**
|
/**
|
||||||
* Sets the file to upload alongside the embed. This file can be accessed via `attachment://fileName.extension` when
|
* Sets the file to upload alongside the embed. This file can be accessed via `attachment://fileName.extension` when
|
||||||
* setting an embed image or author/footer icons. Only one file may be attached.
|
* setting an embed image or author/footer icons. Only one file may be attached.
|
||||||
* @param {FileOptions|string} file Local path or URL to the file to attach, or valid FileOptions for a file to attach
|
* @param {FileOptions|string|Attachment} file Local path or URL to the file to attach,
|
||||||
|
* or valid FileOptions for a file to attach
|
||||||
* @returns {RichEmbed} This embed
|
* @returns {RichEmbed} This embed
|
||||||
*/
|
*/
|
||||||
attachFile(file) {
|
attachFile(file) {
|
||||||
if (this.file) throw new RangeError('You may not upload more than one file at once.');
|
if (this.file) throw new RangeError('You may not upload more than one file at once.');
|
||||||
|
if (file instanceof Attachment) file = file.file;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ class Role {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an object mapping permission names to whether or not the role enables that permission
|
* Get an object mapping permission names to whether or not the role enables that permission.
|
||||||
* @returns {Object<string, boolean>}
|
* @returns {Object<string, boolean>}
|
||||||
* @example
|
* @example
|
||||||
* // Print the serialized role permissions
|
* // Print the serialized role permissions
|
||||||
@@ -195,64 +195,68 @@ class Role {
|
|||||||
* @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number
|
* @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number
|
||||||
* @property {boolean} [hoist] Whether or not the role should be hoisted
|
* @property {boolean} [hoist] Whether or not the role should be hoisted
|
||||||
* @property {number} [position] The position of the role
|
* @property {number} [position] The position of the role
|
||||||
* @property {string[]} [permissions] The permissions of the role
|
* @property {PermissionResolvable[]|number} [permissions] The permissions of the role
|
||||||
* @property {boolean} [mentionable] Whether or not the role should be mentionable
|
* @property {boolean} [mentionable] Whether or not the role should be mentionable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the role.
|
* Edits the role.
|
||||||
* @param {RoleData} data The new data for the role
|
* @param {RoleData} data The new data for the role
|
||||||
|
* @param {string} [reason] The reason for editing this role
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Edit a role
|
* // Edit a role
|
||||||
* role.edit({name: 'new role'})
|
* role.edit({name: 'new role'})
|
||||||
* .then(r => console.log(`Edited role ${r}`))
|
* .then(r => console.log(`Edited role ${r}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
edit(data) {
|
edit(data, reason) {
|
||||||
return this.client.rest.methods.updateGuildRole(this, data);
|
return this.client.rest.methods.updateGuildRole(this, data, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a new name for the role.
|
* Set a new name for the role.
|
||||||
* @param {string} name The new name of the role
|
* @param {string} name The new name of the role
|
||||||
|
* @param {string} [reason] Reason for changing the role's name
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the name of the role
|
* // Set the name of the role
|
||||||
* role.setName('new role')
|
* role.setName('new role')
|
||||||
* .then(r => console.log(`Edited name of role ${r}`))
|
* .then(r => console.log(`Edited name of role ${r}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setName(name) {
|
setName(name, reason) {
|
||||||
return this.edit({ name });
|
return this.edit({ name }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a new color for the role.
|
* Set a new color for the role.
|
||||||
* @param {ColorResolvable} color The color of the role
|
* @param {ColorResolvable} color The color of the role
|
||||||
|
* @param {string} [reason] Reason for changing the role's color
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the color of a role
|
* // Set the color of a role
|
||||||
* role.setColor('#FF0000')
|
* role.setColor('#FF0000')
|
||||||
* .then(r => console.log(`Set color of role ${r}`))
|
* .then(r => console.log(`Set color of role ${r}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setColor(color) {
|
setColor(color, reason) {
|
||||||
return this.edit({ color });
|
return this.edit({ color }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether or not the role should be hoisted.
|
* Set whether or not the role should be hoisted.
|
||||||
* @param {boolean} hoist Whether or not to hoist the role
|
* @param {boolean} hoist Whether or not to hoist the role
|
||||||
|
* @param {string} [reason] Reason for setting whether or not the role should be hoisted
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the hoist of the role
|
* // Set the hoist of the role
|
||||||
* role.setHoist(true)
|
* role.setHoist(true)
|
||||||
* .then(r => console.log(`Role hoisted: ${r.hoist}`))
|
* .then(r => console.log(`Role hoisted: ${r.hoist}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setHoist(hoist) {
|
setHoist(hoist, reason) {
|
||||||
return this.edit({ hoist });
|
return this.edit({ hoist }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,8 +267,8 @@ class Role {
|
|||||||
* @example
|
* @example
|
||||||
* // Set the position of the role
|
* // Set the position of the role
|
||||||
* role.setPosition(1)
|
* role.setPosition(1)
|
||||||
* .then(r => console.log(`Role position: ${r.position}`))
|
* .then(r => console.log(`Role position: ${r.position}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setPosition(position, relative) {
|
setPosition(position, relative) {
|
||||||
return this.guild.setRolePosition(this, position, relative).then(() => this);
|
return this.guild.setRolePosition(this, position, relative).then(() => this);
|
||||||
@@ -273,42 +277,45 @@ class Role {
|
|||||||
/**
|
/**
|
||||||
* Set the permissions of the role.
|
* Set the permissions of the role.
|
||||||
* @param {string[]} permissions The permissions of the role
|
* @param {string[]} permissions The permissions of the role
|
||||||
|
* @param {string} [reason] Reason for changing the role's permissions
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the permissions of the role
|
* // Set the permissions of the role
|
||||||
* role.setPermissions(['KICK_MEMBERS', 'BAN_MEMBERS'])
|
* role.setPermissions(['KICK_MEMBERS', 'BAN_MEMBERS'])
|
||||||
* .then(r => console.log(`Role updated ${r}`))
|
* .then(r => console.log(`Role updated ${r}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setPermissions(permissions) {
|
setPermissions(permissions, reason) {
|
||||||
return this.edit({ permissions });
|
return this.edit({ permissions }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether this role is mentionable.
|
* Set whether this role is mentionable.
|
||||||
* @param {boolean} mentionable Whether this role should be mentionable
|
* @param {boolean} mentionable Whether this role should be mentionable
|
||||||
|
* @param {string} [reason] Reason for setting whether or not this role should be mentionable
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Make the role mentionable
|
* // Make the role mentionable
|
||||||
* role.setMentionable(true)
|
* role.setMentionable(true)
|
||||||
* .then(r => console.log(`Role updated ${r}`))
|
* .then(r => console.log(`Role updated ${r}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setMentionable(mentionable) {
|
setMentionable(mentionable, reason) {
|
||||||
return this.edit({ mentionable });
|
return this.edit({ mentionable }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the role.
|
* Deletes the role.
|
||||||
|
* @param {string} [reason] Reason for deleting the role
|
||||||
* @returns {Promise<Role>}
|
* @returns {Promise<Role>}
|
||||||
* @example
|
* @example
|
||||||
* // Delete a role
|
* // Delete a role
|
||||||
* role.delete()
|
* role.delete()
|
||||||
* .then(r => console.log(`Deleted role ${r}`))
|
* .then(r => console.log(`Deleted role ${r}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete(reason) {
|
||||||
return this.client.rest.methods.deleteGuildRole(this);
|
return this.client.rest.methods.deleteGuildRole(this, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ class TextChannel extends GuildChannel {
|
|||||||
*/
|
*/
|
||||||
this.topic = data.topic;
|
this.topic = data.topic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the Discord considers this channel NSFW
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.nsfw = Boolean(data.nsfw);
|
||||||
|
|
||||||
this.lastMessageID = data.last_message_id;
|
this.lastMessageID = data.last_message_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,15 +49,6 @@ class TextChannel extends GuildChannel {
|
|||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the Discord considers this channel NSFW
|
|
||||||
* @type {boolean}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
get nsfw() {
|
|
||||||
return /^nsfw(-|$)/.test(this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch all webhooks for the channel.
|
* Fetch all webhooks for the channel.
|
||||||
* @returns {Promise<Collection<Snowflake, Webhook>>}
|
* @returns {Promise<Collection<Snowflake, Webhook>>}
|
||||||
@@ -62,23 +60,22 @@ class TextChannel extends GuildChannel {
|
|||||||
/**
|
/**
|
||||||
* Create a webhook for the channel.
|
* Create a webhook for the channel.
|
||||||
* @param {string} name The name of the webhook
|
* @param {string} name The name of the webhook
|
||||||
* @param {BufferResolvable|Base64Resolvable} avatar The avatar for the webhook
|
* @param {BufferResolvable|Base64Resolvable} [avatar] The avatar for the webhook
|
||||||
|
* @param {string} [reason] Reason for creating this webhook
|
||||||
* @returns {Promise<Webhook>} webhook The created webhook
|
* @returns {Promise<Webhook>} webhook The created webhook
|
||||||
* @example
|
* @example
|
||||||
* channel.createWebhook('Snek', 'http://snek.s3.amazonaws.com/topSnek.png')
|
* channel.createWebhook('Snek', 'https://i.imgur.com/mI8XcpG.jpg')
|
||||||
* .then(webhook => console.log(`Created webhook ${webhook}`))
|
* .then(webhook => console.log(`Created webhook ${webhook}`))
|
||||||
* .catch(console.error)
|
* .catch(console.error)
|
||||||
*/
|
*/
|
||||||
createWebhook(name, avatar) {
|
createWebhook(name, avatar, reason) {
|
||||||
return new Promise(resolve => {
|
if (typeof avatar === 'string' && avatar.startsWith('data:')) {
|
||||||
if (typeof avatar === 'string' && avatar.startsWith('data:')) {
|
return this.client.rest.methods.createWebhook(this, name, avatar, reason);
|
||||||
resolve(this.client.rest.methods.createWebhook(this, name, avatar));
|
} else {
|
||||||
} else {
|
return this.client.resolver.resolveImage(avatar).then(data =>
|
||||||
this.client.resolver.resolveBuffer(avatar).then(data =>
|
this.client.rest.methods.createWebhook(this, name, data, reason)
|
||||||
resolve(this.client.rest.methods.createWebhook(this, name, data))
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ const Snowflake = require('../util/Snowflake');
|
|||||||
class User {
|
class User {
|
||||||
constructor(client, data) {
|
constructor(client, data) {
|
||||||
/**
|
/**
|
||||||
* The client that created the instance of the the user
|
* The client that created the instance of the user
|
||||||
* @name User#client
|
* @name User#client
|
||||||
* @type {}
|
* @type {Client}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
Object.defineProperty(this, 'client', { value: client });
|
Object.defineProperty(this, 'client', { value: client });
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class UserProfile {
|
|||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The client that created the instance of the the UserProfile.
|
* The client that created the instance of the UserProfile
|
||||||
* @name UserProfile#client
|
* @name UserProfile#client
|
||||||
* @type {Client}
|
* @type {Client}
|
||||||
* @readonly
|
* @readonly
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class VoiceChannel extends GuildChannel {
|
|||||||
* The bitrate of this voice channel
|
* The bitrate of this voice channel
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.bitrate = data.bitrate;
|
this.bitrate = data.bitrate * 0.001;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum amount of users allowed in this channel - 0 means unlimited.
|
* The maximum amount of users allowed in this channel - 0 means unlimited.
|
||||||
@@ -76,31 +76,34 @@ class VoiceChannel extends GuildChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the bitrate of the channel.
|
* Sets the bitrate of the channel (in kbps).
|
||||||
* @param {number} bitrate The new bitrate
|
* @param {number} bitrate The new bitrate
|
||||||
|
* @param {string} [reason] Reason for changing the channel's bitrate
|
||||||
* @returns {Promise<VoiceChannel>}
|
* @returns {Promise<VoiceChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the bitrate of a voice channel
|
* // Set the bitrate of a voice channel
|
||||||
* voiceChannel.setBitrate(48000)
|
* voiceChannel.setBitrate(48)
|
||||||
* .then(vc => console.log(`Set bitrate to ${vc.bitrate} for ${vc.name}`))
|
* .then(vc => console.log(`Set bitrate to ${vc.bitrate}kbps for ${vc.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setBitrate(bitrate) {
|
setBitrate(bitrate, reason) {
|
||||||
return this.edit({ bitrate });
|
bitrate *= 1000;
|
||||||
|
return this.edit({ bitrate }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the user limit of the channel.
|
* Sets the user limit of the channel.
|
||||||
* @param {number} userLimit The new user limit
|
* @param {number} userLimit The new user limit
|
||||||
|
* @param {string} [reason] Reason for changing the user limit
|
||||||
* @returns {Promise<VoiceChannel>}
|
* @returns {Promise<VoiceChannel>}
|
||||||
* @example
|
* @example
|
||||||
* // Set the user limit of a voice channel
|
* // Set the user limit of a voice channel
|
||||||
* voiceChannel.setUserLimit(42)
|
* voiceChannel.setUserLimit(42)
|
||||||
* .then(vc => console.log(`Set user limit to ${vc.userLimit} for ${vc.name}`))
|
* .then(vc => console.log(`Set user limit to ${vc.userLimit} for ${vc.name}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
setUserLimit(userLimit) {
|
setUserLimit(userLimit, reason) {
|
||||||
return this.edit({ userLimit });
|
return this.edit({ userLimit }, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,8 +112,8 @@ class VoiceChannel extends GuildChannel {
|
|||||||
* @example
|
* @example
|
||||||
* // Join a voice channel
|
* // Join a voice channel
|
||||||
* voiceChannel.join()
|
* voiceChannel.join()
|
||||||
* .then(connection => console.log('Connected!'))
|
* .then(connection => console.log('Connected!'))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
join() {
|
join() {
|
||||||
if (this.client.browser) return Promise.reject(new Error('Voice connections are not available in browsers.'));
|
if (this.client.browser) return Promise.reject(new Error('Voice connections are not available in browsers.'));
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const Util = require('../util/Util');
|
||||||
|
const Attachment = require('./Attachment');
|
||||||
|
const RichEmbed = require('./RichEmbed');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a webhook.
|
* Represents a webhook.
|
||||||
@@ -36,7 +39,7 @@ class Webhook {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The avatar for the webhook
|
* The avatar for the webhook
|
||||||
* @type {string}
|
* @type {?string}
|
||||||
*/
|
*/
|
||||||
this.avatar = data.avatar;
|
this.avatar = data.avatar;
|
||||||
|
|
||||||
@@ -76,11 +79,12 @@ class Webhook {
|
|||||||
* @property {string} [avatarURL] Avatar URL override for the message
|
* @property {string} [avatarURL] Avatar URL override for the message
|
||||||
* @property {boolean} [tts=false] Whether or not the message should be spoken aloud
|
* @property {boolean} [tts=false] Whether or not the message should be spoken aloud
|
||||||
* @property {string} [nonce=''] The nonce for the message
|
* @property {string} [nonce=''] The nonce for the message
|
||||||
* @property {Object[]} [embeds] An array of embeds for the message
|
* @property {Array<RichEmbed|Object>} [embeds] An array of embeds for the message
|
||||||
* (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
|
* (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
|
||||||
* @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here
|
* @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here
|
||||||
* should be replaced with plain-text
|
* should be replaced with plain-text
|
||||||
* @property {FileOptions|string} [file] A file to send with the message
|
* @property {FileOptions|BufferResolvable|Attachment} [file] A file to send with the message **(deprecated)**
|
||||||
|
* @property {FileOptions[]|BufferResolvable[]|Attachment[]} [files] Files to send with the message
|
||||||
* @property {string|boolean} [code] Language for optional codeblock formatting to apply
|
* @property {string|boolean} [code] Language for optional codeblock formatting to apply
|
||||||
* @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if
|
* @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if
|
||||||
* it exceeds the character limit. If an object is provided, these are the options for splitting the message.
|
* it exceeds the character limit. If an object is provided, these are the options for splitting the message.
|
||||||
@@ -89,39 +93,87 @@ class Webhook {
|
|||||||
/**
|
/**
|
||||||
* Send a message with this webhook.
|
* Send a message with this webhook.
|
||||||
* @param {StringResolvable} content The content to send
|
* @param {StringResolvable} content The content to send
|
||||||
* @param {WebhookMessageOptions} [options={}] The options to provide
|
* @param {WebhookMessageOptions|Attachment|RichEmbed} [options] The options to provide
|
||||||
|
* can also be just a RichEmbed or Attachment
|
||||||
* @returns {Promise<Message|Message[]>}
|
* @returns {Promise<Message|Message[]>}
|
||||||
* @example
|
* @example
|
||||||
* // Send a message
|
* // Send a message
|
||||||
* webhook.send('hello!')
|
* webhook.send('hello!')
|
||||||
* .then(message => console.log(`Sent message: ${message.content}`))
|
* .then(message => console.log(`Sent message: ${message.content}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
send(content, options) {
|
send(content, options) { // eslint-disable-line complexity
|
||||||
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||||
options = content;
|
options = content;
|
||||||
content = '';
|
content = '';
|
||||||
} else if (!options) {
|
} else if (!options) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
if (options.file) {
|
|
||||||
if (typeof options.file === 'string') options.file = { attachment: options.file };
|
if (options instanceof Attachment) options = { files: [options] };
|
||||||
if (!options.file.name) {
|
if (options instanceof RichEmbed) options = { embeds: [options] };
|
||||||
if (typeof options.file.attachment === 'string') {
|
|
||||||
options.file.name = path.basename(options.file.attachment);
|
if (content) {
|
||||||
} else if (options.file.attachment && options.file.attachment.path) {
|
content = this.client.resolver.resolveString(content);
|
||||||
options.file.name = path.basename(options.file.attachment.path);
|
let { split, code, disableEveryone } = options;
|
||||||
} else {
|
if (split && typeof split !== 'object') split = {};
|
||||||
options.file.name = 'file.jpg';
|
if (typeof code !== 'undefined' && (typeof code !== 'boolean' || code === true)) {
|
||||||
|
content = Util.escapeMarkdown(content, true);
|
||||||
|
content = `\`\`\`${typeof code !== 'boolean' ? code || '' : ''}\n${content}\n\`\`\``;
|
||||||
|
if (split) {
|
||||||
|
split.prepend = `\`\`\`${typeof code !== 'boolean' ? code || '' : ''}\n`;
|
||||||
|
split.append = '\n```';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.client.resolver.resolveBuffer(options.file.attachment).then(file =>
|
if (disableEveryone || (typeof disableEveryone === 'undefined' && this.client.options.disableEveryone)) {
|
||||||
this.client.rest.methods.sendWebhookMessage(this, content, options, {
|
content = content.replace(/@(everyone|here)/g, '@\u200b$1');
|
||||||
file,
|
}
|
||||||
name: options.file.name,
|
|
||||||
})
|
if (split) content = Util.splitMessage(content, split);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.file) {
|
||||||
|
if (options.files) options.files.push(options.file);
|
||||||
|
else options.files = [options.file];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.embeds) {
|
||||||
|
const files = [];
|
||||||
|
for (const embed of options.embeds) {
|
||||||
|
if (embed.file) files.push(embed.file);
|
||||||
|
}
|
||||||
|
if (options.files) options.files.push(...files);
|
||||||
|
else options.files = files;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.files) {
|
||||||
|
for (let i = 0; i < options.files.length; i++) {
|
||||||
|
let file = options.files[i];
|
||||||
|
if (typeof file === 'string' || Buffer.isBuffer(file)) file = { attachment: file };
|
||||||
|
if (!file.name) {
|
||||||
|
if (typeof file.attachment === 'string') {
|
||||||
|
file.name = path.basename(file.attachment);
|
||||||
|
} else if (file.attachment && file.attachment.path) {
|
||||||
|
file.name = path.basename(file.attachment.path);
|
||||||
|
} else if (file instanceof Attachment) {
|
||||||
|
file = { attachment: file.file, name: path.basename(file.file) || 'file.jpg' };
|
||||||
|
} else {
|
||||||
|
file.name = 'file.jpg';
|
||||||
|
}
|
||||||
|
} else if (file instanceof Attachment) {
|
||||||
|
file = file.file;
|
||||||
|
}
|
||||||
|
options.files[i] = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(options.files.map(file =>
|
||||||
|
this.client.resolver.resolveFile(file.attachment).then(resource => {
|
||||||
|
file.file = resource;
|
||||||
|
return file;
|
||||||
|
})
|
||||||
|
)).then(files => this.client.rest.methods.sendWebhookMessage(this, content, options, files));
|
||||||
|
}
|
||||||
|
|
||||||
return this.client.rest.methods.sendWebhookMessage(this, content, options);
|
return this.client.rest.methods.sendWebhookMessage(this, content, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +182,7 @@ class Webhook {
|
|||||||
* @param {StringResolvable} content The content to send
|
* @param {StringResolvable} content The content to send
|
||||||
* @param {WebhookMessageOptions} [options={}] The options to provide
|
* @param {WebhookMessageOptions} [options={}] The options to provide
|
||||||
* @returns {Promise<Message|Message[]>}
|
* @returns {Promise<Message|Message[]>}
|
||||||
|
* @deprecated
|
||||||
* @example
|
* @example
|
||||||
* // Send a message
|
* // Send a message
|
||||||
* webhook.sendMessage('hello!')
|
* webhook.sendMessage('hello!')
|
||||||
@@ -147,6 +200,7 @@ class Webhook {
|
|||||||
* @param {StringResolvable} [content] Text message to send with the attachment
|
* @param {StringResolvable} [content] Text message to send with the attachment
|
||||||
* @param {WebhookMessageOptions} [options] The options to provide
|
* @param {WebhookMessageOptions} [options] The options to provide
|
||||||
* @returns {Promise<Message>}
|
* @returns {Promise<Message>}
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
sendFile(attachment, name, content, options = {}) {
|
sendFile(attachment, name, content, options = {}) {
|
||||||
return this.send(content, Object.assign(options, { file: { attachment, name } }));
|
return this.send(content, Object.assign(options, { file: { attachment, name } }));
|
||||||
@@ -158,6 +212,7 @@ class Webhook {
|
|||||||
* @param {StringResolvable} content Content of the code block
|
* @param {StringResolvable} content Content of the code block
|
||||||
* @param {WebhookMessageOptions} options The options to provide
|
* @param {WebhookMessageOptions} options The options to provide
|
||||||
* @returns {Promise<Message|Message[]>}
|
* @returns {Promise<Message|Message[]>}
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
sendCode(lang, content, options = {}) {
|
sendCode(lang, content, options = {}) {
|
||||||
return this.send(content, Object.assign(options, { code: lang }));
|
return this.send(content, Object.assign(options, { code: lang }));
|
||||||
@@ -187,28 +242,25 @@ class Webhook {
|
|||||||
/**
|
/**
|
||||||
* Edit the webhook.
|
* Edit the webhook.
|
||||||
* @param {string} name The new name for the webhook
|
* @param {string} name The new name for the webhook
|
||||||
* @param {BufferResolvable} avatar The new avatar for the webhook
|
* @param {BufferResolvable} [avatar] The new avatar for the webhook
|
||||||
* @returns {Promise<Webhook>}
|
* @returns {Promise<Webhook>}
|
||||||
*/
|
*/
|
||||||
edit(name = this.name, avatar) {
|
edit(name = this.name, avatar) {
|
||||||
if (avatar) {
|
if (avatar) {
|
||||||
return this.client.resolver.resolveBuffer(avatar).then(file => {
|
return this.client.resolver.resolveImage(avatar).then(data =>
|
||||||
const dataURI = this.client.resolver.resolveBase64(file);
|
this.client.rest.methods.editWebhook(this, name, data)
|
||||||
return this.client.rest.methods.editWebhook(this, name, dataURI);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return this.client.rest.methods.editWebhook(this, name).then(data => {
|
return this.client.rest.methods.editWebhook(this, name);
|
||||||
this.setup(data);
|
|
||||||
return this;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the webhook.
|
* Delete the webhook.
|
||||||
|
* @param {string} [reason] Reason for deleting the webhook
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete(reason) {
|
||||||
return this.client.rest.methods.deleteWebhook(this);
|
return this.client.rest.methods.deleteWebhook(this, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ const EventEmitter = require('events').EventEmitter;
|
|||||||
* Filter to be applied to the collector.
|
* Filter to be applied to the collector.
|
||||||
* @typedef {Function} CollectorFilter
|
* @typedef {Function} CollectorFilter
|
||||||
* @param {...*} args Any arguments received by the listener
|
* @param {...*} args Any arguments received by the listener
|
||||||
* @returns {boolean} To collect or not collect
|
* @param {Collection} collection The items collected by this collector
|
||||||
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +79,7 @@ class Collector extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
_handle(...args) {
|
_handle(...args) {
|
||||||
const collect = this.handle(...args);
|
const collect = this.handle(...args);
|
||||||
if (!collect || !this.filter(...args)) return;
|
if (!collect || !this.filter(...args, this.collected)) return;
|
||||||
|
|
||||||
this.collected.set(collect.key, collect.value);
|
this.collected.set(collect.key, collect.value);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ const path = require('path');
|
|||||||
const Message = require('../Message');
|
const Message = require('../Message');
|
||||||
const MessageCollector = require('../MessageCollector');
|
const MessageCollector = require('../MessageCollector');
|
||||||
const Collection = require('../../util/Collection');
|
const Collection = require('../../util/Collection');
|
||||||
|
const Attachment = require('../../structures/Attachment');
|
||||||
|
const RichEmbed = require('../../structures/RichEmbed');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,8 +40,8 @@ class TextBasedChannel {
|
|||||||
* (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
|
* (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
|
||||||
* @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here
|
* @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here
|
||||||
* should be replaced with plain-text
|
* should be replaced with plain-text
|
||||||
* @property {FileOptions|string} [file] A file to send with the message **(deprecated)**
|
* @property {FileOptions|BufferResolvable|Attachment} [file] A file to send with the message **(deprecated)**
|
||||||
* @property {FileOptions[]|string[]} [files] Files to send with the message
|
* @property {FileOptions[]|BufferResolvable[]|Attachment[]} [files] Files to send with the message
|
||||||
* @property {string|boolean} [code] Language for optional codeblock formatting to apply
|
* @property {string|boolean} [code] Language for optional codeblock formatting to apply
|
||||||
* @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if
|
* @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if
|
||||||
* it exceeds the character limit. If an object is provided, these are the options for splitting the message
|
* it exceeds the character limit. If an object is provided, these are the options for splitting the message
|
||||||
@@ -64,13 +66,14 @@ class TextBasedChannel {
|
|||||||
/**
|
/**
|
||||||
* Send a message to this channel.
|
* Send a message to this channel.
|
||||||
* @param {StringResolvable} [content] Text for the message
|
* @param {StringResolvable} [content] Text for the message
|
||||||
* @param {MessageOptions} [options={}] Options for the message
|
* @param {MessageOptions|Attachment|RichEmbed} [options] Options for the message,
|
||||||
|
* can also be just a RichEmbed or Attachment
|
||||||
* @returns {Promise<Message|Message[]>}
|
* @returns {Promise<Message|Message[]>}
|
||||||
* @example
|
* @example
|
||||||
* // Send a message
|
* // Send a message
|
||||||
* channel.send('hello!')
|
* channel.send('hello!')
|
||||||
* .then(message => console.log(`Sent message: ${message.content}`))
|
* .then(message => console.log(`Sent message: ${message.content}`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
send(content, options) {
|
send(content, options) {
|
||||||
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
if (!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||||
@@ -80,7 +83,13 @@ class TextBasedChannel {
|
|||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.embed && options.embed.file) options.file = options.embed.file;
|
if (options instanceof Attachment) options = { files: [options.file] };
|
||||||
|
if (options instanceof RichEmbed) options = { embed: options };
|
||||||
|
|
||||||
|
if (options.embed && options.embed.file) {
|
||||||
|
if (options.files) options.files.push(options.embed.file);
|
||||||
|
else options.files = [options.embed.file];
|
||||||
|
}
|
||||||
|
|
||||||
if (options.file) {
|
if (options.file) {
|
||||||
if (options.files) options.files.push(options.file);
|
if (options.files) options.files.push(options.file);
|
||||||
@@ -88,24 +97,28 @@ class TextBasedChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.files) {
|
if (options.files) {
|
||||||
for (const i in options.files) {
|
for (let i = 0; i < options.files.length; i++) {
|
||||||
let file = options.files[i];
|
let file = options.files[i];
|
||||||
if (typeof file === 'string') file = { attachment: file };
|
if (typeof file === 'string' || Buffer.isBuffer(file)) file = { attachment: file };
|
||||||
if (!file.name) {
|
if (!file.name) {
|
||||||
if (typeof file.attachment === 'string') {
|
if (typeof file.attachment === 'string') {
|
||||||
file.name = path.basename(file.attachment);
|
file.name = path.basename(file.attachment);
|
||||||
} else if (file.attachment && file.attachment.path) {
|
} else if (file.attachment && file.attachment.path) {
|
||||||
file.name = path.basename(file.attachment.path);
|
file.name = path.basename(file.attachment.path);
|
||||||
|
} else if (file instanceof Attachment) {
|
||||||
|
file = { attachment: file.file, name: path.basename(file.file) || 'file.jpg' };
|
||||||
} else {
|
} else {
|
||||||
file.name = 'file.jpg';
|
file.name = 'file.jpg';
|
||||||
}
|
}
|
||||||
|
} else if (file instanceof Attachment) {
|
||||||
|
file = file.file;
|
||||||
}
|
}
|
||||||
options.files[i] = file;
|
options.files[i] = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(options.files.map(file =>
|
return Promise.all(options.files.map(file =>
|
||||||
this.client.resolver.resolveBuffer(file.attachment).then(buffer => {
|
this.client.resolver.resolveFile(file.attachment).then(resource => {
|
||||||
file.file = buffer;
|
file.file = resource;
|
||||||
return file;
|
return file;
|
||||||
})
|
})
|
||||||
)).then(files => this.client.rest.methods.sendMessage(this, content, options, files));
|
)).then(files => this.client.rest.methods.sendMessage(this, content, options, files));
|
||||||
@@ -158,8 +171,8 @@ class TextBasedChannel {
|
|||||||
* @example
|
* @example
|
||||||
* // Get messages
|
* // Get messages
|
||||||
* channel.fetchMessages({limit: 10})
|
* channel.fetchMessages({limit: 10})
|
||||||
* .then(messages => console.log(`Received ${messages.size} messages`))
|
* .then(messages => console.log(`Received ${messages.size} messages`))
|
||||||
* .catch(console.error);
|
* .catch(console.error);
|
||||||
*/
|
*/
|
||||||
fetchMessages(options = {}) {
|
fetchMessages(options = {}) {
|
||||||
return this.client.rest.methods.getChannelMessages(this, options).then(data => {
|
return this.client.rest.methods.getChannelMessages(this, options).then(data => {
|
||||||
@@ -214,15 +227,21 @@ class TextBasedChannel {
|
|||||||
* @property {Date} [before] Date to find messages before
|
* @property {Date} [before] Date to find messages before
|
||||||
* @property {Date} [after] Date to find messages before
|
* @property {Date} [after] Date to find messages before
|
||||||
* @property {Date} [during] Date to find messages during (range of date to date + 24 hours)
|
* @property {Date} [during] Date to find messages during (range of date to date + 24 hours)
|
||||||
|
* @property {boolean} [nsfw=false] Include results from NSFW channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} MessageSearchResult
|
||||||
|
* @property {number} totalResults Total result count
|
||||||
|
* @property {Message[][]} messages Array of message results
|
||||||
|
* The message which has triggered the result will have the `hit` property set to `true`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a search within the channel.
|
* Performs a search within the channel.
|
||||||
* <warn>This is only available when using a user account.</warn>
|
* <warn>This is only available when using a user account.</warn>
|
||||||
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
||||||
* @returns {Promise<Array<Message[]>>}
|
* @returns {Promise<MessageSearchResult>}
|
||||||
* An array containing arrays of messages. Each inner array is a search context cluster
|
|
||||||
* The message which has triggered the result will have the `hit` property set to `true`
|
|
||||||
* @example
|
* @example
|
||||||
* channel.search({
|
* channel.search({
|
||||||
* content: 'discord.js',
|
* content: 'discord.js',
|
||||||
@@ -319,11 +338,11 @@ class TextBasedChannel {
|
|||||||
* @returns {MessageCollector}
|
* @returns {MessageCollector}
|
||||||
* @example
|
* @example
|
||||||
* // Create a message collector
|
* // Create a message collector
|
||||||
* const collector = channel.createCollector(
|
* const collector = channel.createMessageCollector(
|
||||||
* m => m.content.includes('discord'),
|
* m => m.content.includes('discord'),
|
||||||
* { time: 15000 }
|
* { time: 15000 }
|
||||||
* );
|
* );
|
||||||
* collector.on('message', m => console.log(`Collected ${m.content}`));
|
* collector.on('collect', m => console.log(`Collected ${m.content}`));
|
||||||
* collector.on('end', collected => console.log(`Collected ${collected.size} items`));
|
* collector.on('end', collected => console.log(`Collected ${collected.size} items`));
|
||||||
*/
|
*/
|
||||||
createMessageCollector(filter, options = {}) {
|
createMessageCollector(filter, options = {}) {
|
||||||
@@ -347,8 +366,8 @@ class TextBasedChannel {
|
|||||||
* const filter = m => m.content.startsWith('!vote');
|
* const filter = m => m.content.startsWith('!vote');
|
||||||
* // Errors: ['time'] treats ending because of the time limit as an error
|
* // Errors: ['time'] treats ending because of the time limit as an error
|
||||||
* channel.awaitMessages(filter, { max: 4, time: 60000, errors: ['time'] })
|
* channel.awaitMessages(filter, { max: 4, time: 60000, errors: ['time'] })
|
||||||
* .then(collected => console.log(collected.size))
|
* .then(collected => console.log(collected.size))
|
||||||
* .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));
|
* .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));
|
||||||
*/
|
*/
|
||||||
awaitMessages(filter, options = {}) {
|
awaitMessages(filter, options = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
@@ -59,59 +59,99 @@ class Collection extends Map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the first item in this collection.
|
* Obtains the first value(s) in this collection.
|
||||||
* @returns {*}
|
* @param {number} [count] Number of values to obtain from the beginning
|
||||||
|
* @returns {*|Array<*>} The single value if `count` is undefined, or an array of values of `count` length
|
||||||
*/
|
*/
|
||||||
first() {
|
first(count) {
|
||||||
return this.values().next().value;
|
if (count === undefined) return this.values().next().value;
|
||||||
|
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
|
||||||
|
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
|
||||||
|
count = Math.min(this.size, count);
|
||||||
|
const arr = new Array(count);
|
||||||
|
const iter = this.values();
|
||||||
|
for (let i = 0; i < count; i++) arr[i] = iter.next().value;
|
||||||
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the first key in this collection.
|
* Obtains the first key(s) in this collection.
|
||||||
* @returns {*}
|
* @param {number} [count] Number of keys to obtain from the beginning
|
||||||
|
* @returns {*|Array<*>} The single key if `count` is undefined, or an array of keys of `count` length
|
||||||
*/
|
*/
|
||||||
firstKey() {
|
firstKey(count) {
|
||||||
return this.keys().next().value;
|
if (count === undefined) return this.keys().next().value;
|
||||||
|
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
|
||||||
|
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
|
||||||
|
count = Math.min(this.size, count);
|
||||||
|
const arr = new Array(count);
|
||||||
|
const iter = this.iter();
|
||||||
|
for (let i = 0; i < count; i++) arr[i] = iter.next().value;
|
||||||
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the last item in this collection. This relies on the `array()` method, and thus the caching mechanism
|
* Obtains the last value(s) in this collection. This relies on {@link Collection#array}, and thus the caching
|
||||||
* applies here as well.
|
* mechanism applies here as well.
|
||||||
* @returns {*}
|
* @param {number} [count] Number of values to obtain from the end
|
||||||
|
* @returns {*|Array<*>} The single value if `count` is undefined, or an array of values of `count` length
|
||||||
*/
|
*/
|
||||||
last() {
|
last(count) {
|
||||||
const arr = this.array();
|
const arr = this.array();
|
||||||
return arr[arr.length - 1];
|
if (count === undefined) return arr[arr.length - 1];
|
||||||
|
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
|
||||||
|
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
|
||||||
|
return arr.slice(-count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the last key in this collection. This relies on the `keyArray()` method, and thus the caching mechanism
|
* Obtains the last key(s) in this collection. This relies on {@link Collection#keyArray}, and thus the caching
|
||||||
* applies here as well.
|
* mechanism applies here as well.
|
||||||
* @returns {*}
|
* @param {number} [count] Number of keys to obtain from the end
|
||||||
|
* @returns {*|Array<*>} The single key if `count` is undefined, or an array of keys of `count` length
|
||||||
*/
|
*/
|
||||||
lastKey() {
|
lastKey(count) {
|
||||||
const arr = this.keyArray();
|
const arr = this.keyArray();
|
||||||
return arr[arr.length - 1];
|
if (count === undefined) return arr[arr.length - 1];
|
||||||
|
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
|
||||||
|
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
|
||||||
|
return arr.slice(-count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a random item from this collection. This relies on the `array()` method, and thus the caching mechanism
|
* Obtains random value(s) from this collection. This relies on {@link Collection#array}, and thus the caching
|
||||||
* applies here as well.
|
* mechanism applies here as well.
|
||||||
* @returns {*}
|
* @param {number} [count] Number of values to obtain randomly
|
||||||
|
* @returns {*|Array<*>} The single value if `count` is undefined, or an array of values of `count` length
|
||||||
*/
|
*/
|
||||||
random() {
|
random(count) {
|
||||||
const arr = this.array();
|
let arr = this.array();
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
if (count === undefined) return arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
|
||||||
|
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
|
||||||
|
if (arr.length === 0) return [];
|
||||||
|
const rand = new Array(count);
|
||||||
|
arr = arr.slice();
|
||||||
|
for (let i = 0; i < count; i++) rand[i] = arr.splice(Math.floor(Math.random() * arr.length), 1)[0];
|
||||||
|
return rand;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a random key from this collection. This relies on the `keyArray()` method, and thus the caching mechanism
|
* Obtains random key(s) from this collection. This relies on {@link Collection#keyArray}, and thus the caching
|
||||||
* applies here as well.
|
* mechanism applies here as well.
|
||||||
* @returns {*}
|
* @param {number} [count] Number of keys to obtain randomly
|
||||||
|
* @returns {*|Array<*>} The single key if `count` is undefined, or an array of keys of `count` length
|
||||||
*/
|
*/
|
||||||
randomKey() {
|
randomKey(count) {
|
||||||
const arr = this.keyArray();
|
let arr = this.keyArray();
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
if (count === undefined) return arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
|
||||||
|
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
|
||||||
|
if (arr.length === 0) return [];
|
||||||
|
const rand = new Array(count);
|
||||||
|
arr = arr.slice();
|
||||||
|
for (let i = 0; i < count; i++) rand[i] = arr.splice(Math.floor(Math.random() * arr.length), 1)[0];
|
||||||
|
return rand;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ exports.Package = require('../../package.json');
|
|||||||
* 100% certain you don't need, as many are important, but not obviously so. The safest one to disable with the
|
* 100% certain you don't need, as many are important, but not obviously so. The safest one to disable with the
|
||||||
* most impact is typically `TYPING_START`.
|
* most impact is typically `TYPING_START`.
|
||||||
* @property {WebsocketOptions} [ws] Options for the WebSocket
|
* @property {WebsocketOptions} [ws] Options for the WebSocket
|
||||||
|
* @property {HTTPOptions} [http] HTTP options
|
||||||
*/
|
*/
|
||||||
exports.DefaultOptions = {
|
exports.DefaultOptions = {
|
||||||
apiRequestMethod: 'sequential',
|
apiRequestMethod: 'sequential',
|
||||||
@@ -63,6 +64,15 @@ exports.DefaultOptions = {
|
|||||||
},
|
},
|
||||||
version: 6,
|
version: 6,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP options
|
||||||
|
* @typedef {Object} HTTPOptions
|
||||||
|
* @property {number} [version=7] API version to use
|
||||||
|
* @property {string} [api='https://discordapp.com/api'] Base url of the API
|
||||||
|
* @property {string} [cdn='https://cdn.discordapp.com'] Base url of the CDN
|
||||||
|
* @property {string} [invite='https://discord.gg'] Base url of invites
|
||||||
|
*/
|
||||||
http: {
|
http: {
|
||||||
version: 7,
|
version: 7,
|
||||||
host: 'https://discordapp.com',
|
host: 'https://discordapp.com',
|
||||||
@@ -102,7 +112,10 @@ const Endpoints = exports.Endpoints = {
|
|||||||
relationships: `${base}/relationships`,
|
relationships: `${base}/relationships`,
|
||||||
settings: `${base}/settings`,
|
settings: `${base}/settings`,
|
||||||
Relationship: uID => `${base}/relationships/${uID}`,
|
Relationship: uID => `${base}/relationships/${uID}`,
|
||||||
Guild: guildID => `${base}/guilds/${guildID}`,
|
Guild: guildID => ({
|
||||||
|
toString: () => `${base}/guilds/${guildID}`,
|
||||||
|
settings: `${base}/guilds/${guildID}/settings`,
|
||||||
|
}),
|
||||||
Note: id => `${base}/notes/${id}`,
|
Note: id => `${base}/notes/${id}`,
|
||||||
Mentions: (limit, roles, everyone, guildID) =>
|
Mentions: (limit, roles, everyone, guildID) =>
|
||||||
`${base}/mentions?limit=${limit}&roles=${roles}&everyone=${everyone}${guildID ? `&guild_id=${guildID}` : ''}`,
|
`${base}/mentions?limit=${limit}&roles=${roles}&everyone=${everyone}${guildID ? `&guild_id=${guildID}` : ''}`,
|
||||||
@@ -133,7 +146,7 @@ const Endpoints = exports.Endpoints = {
|
|||||||
ack: `${base}/ack`,
|
ack: `${base}/ack`,
|
||||||
settings: `${base}/settings`,
|
settings: `${base}/settings`,
|
||||||
auditLogs: `${base}/audit-logs`,
|
auditLogs: `${base}/audit-logs`,
|
||||||
Emoji: emojiID => Endpoints.CDN(root).Emoji(emojiID),
|
Emoji: emojiID => `${base}/emojis/${emojiID}`,
|
||||||
Icon: (root, hash) => Endpoints.CDN(root).Icon(guildID, hash),
|
Icon: (root, hash) => Endpoints.CDN(root).Icon(guildID, hash),
|
||||||
Splash: (root, hash) => Endpoints.CDN(root).Splash(guildID, hash),
|
Splash: (root, hash) => Endpoints.CDN(root).Splash(guildID, hash),
|
||||||
Role: roleID => `${base}/roles/${roleID}`,
|
Role: roleID => `${base}/roles/${roleID}`,
|
||||||
@@ -164,6 +177,7 @@ const Endpoints = exports.Endpoints = {
|
|||||||
webhooks: `${base}/webhooks`,
|
webhooks: `${base}/webhooks`,
|
||||||
search: `${base}/messages/search`,
|
search: `${base}/messages/search`,
|
||||||
pins: `${base}/pins`,
|
pins: `${base}/pins`,
|
||||||
|
Icon: (root, hash) => Endpoints.CDN(root).GDMIcon(channelID, hash),
|
||||||
Pin: messageID => `${base}/pins/${messageID}`,
|
Pin: messageID => `${base}/pins/${messageID}`,
|
||||||
Recipient: recipientID => `${base}/recipients/${recipientID}`,
|
Recipient: recipientID => `${base}/recipients/${recipientID}`,
|
||||||
Message: messageID => {
|
Message: messageID => {
|
||||||
@@ -192,6 +206,7 @@ const Endpoints = exports.Endpoints = {
|
|||||||
Asset: name => `${root}/assets/${name}`,
|
Asset: name => `${root}/assets/${name}`,
|
||||||
Avatar: (userID, hash) => `${root}/avatars/${userID}/${hash}.${hash.startsWith('a_') ? 'gif' : 'png'}?size=2048`,
|
Avatar: (userID, hash) => `${root}/avatars/${userID}/${hash}.${hash.startsWith('a_') ? 'gif' : 'png'}?size=2048`,
|
||||||
Icon: (guildID, hash) => `${root}/icons/${guildID}/${hash}.jpg`,
|
Icon: (guildID, hash) => `${root}/icons/${guildID}/${hash}.jpg`,
|
||||||
|
GDMIcon: (channelID, hash) => `${root}/channel-icons/${channelID}/${hash}.jpg?size=2048`,
|
||||||
Splash: (guildID, hash) => `${root}/splashes/${guildID}/${hash}.jpg`,
|
Splash: (guildID, hash) => `${root}/splashes/${guildID}/${hash}.jpg`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -200,7 +215,8 @@ const Endpoints = exports.Endpoints = {
|
|||||||
const base = `/oauth2/applications/${appID}`;
|
const base = `/oauth2/applications/${appID}`;
|
||||||
return {
|
return {
|
||||||
toString: () => base,
|
toString: () => base,
|
||||||
reset: `${base}/reset`,
|
resetSecret: `${base}/reset`,
|
||||||
|
resetToken: `${base}/bot/reset`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
App: appID => `/oauth2/authorize?client_id=${appID}`,
|
App: appID => `/oauth2/authorize?client_id=${appID}`,
|
||||||
@@ -212,7 +228,7 @@ const Endpoints = exports.Endpoints = {
|
|||||||
toString: () => '/gateway',
|
toString: () => '/gateway',
|
||||||
bot: '/gateway/bot',
|
bot: '/gateway/bot',
|
||||||
},
|
},
|
||||||
Invite: inviteID => `/invite/${inviteID}`,
|
Invite: inviteID => `/invite/${inviteID}?with_counts=true`,
|
||||||
inviteLink: id => `https://discord.gg/${id}`,
|
inviteLink: id => `https://discord.gg/${id}`,
|
||||||
Webhook: (webhookID, token) => `/webhooks/${webhookID}${token ? `/${token}` : ''}`,
|
Webhook: (webhookID, token) => `/webhooks/${webhookID}${token ? `/${token}` : ''}`,
|
||||||
};
|
};
|
||||||
@@ -220,12 +236,12 @@ const Endpoints = exports.Endpoints = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The current status of the client. Here are the available statuses:
|
* The current status of the client. Here are the available statuses:
|
||||||
* - READY
|
* * READY
|
||||||
* - CONNECTING
|
* * CONNECTING
|
||||||
* - RECONNECTING
|
* * RECONNECTING
|
||||||
* - IDLE
|
* * IDLE
|
||||||
* - NEARLY
|
* * NEARLY
|
||||||
* - DISCONNECTED
|
* * DISCONNECTED
|
||||||
* @typedef {number} Status
|
* @typedef {number} Status
|
||||||
*/
|
*/
|
||||||
exports.Status = {
|
exports.Status = {
|
||||||
@@ -239,11 +255,11 @@ exports.Status = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The current status of a voice connection. Here are the available statuses:
|
* The current status of a voice connection. Here are the available statuses:
|
||||||
* - CONNECTED
|
* * CONNECTED
|
||||||
* - CONNECTING
|
* * CONNECTING
|
||||||
* - AUTHENTICATING
|
* * AUTHENTICATING
|
||||||
* - RECONNECTING
|
* * RECONNECTING
|
||||||
* - DISCONNECTED
|
* * DISCONNECTED
|
||||||
* @typedef {number} VoiceStatus
|
* @typedef {number} VoiceStatus
|
||||||
*/
|
*/
|
||||||
exports.VoiceStatus = {
|
exports.VoiceStatus = {
|
||||||
@@ -287,6 +303,7 @@ exports.VoiceOPCodes = {
|
|||||||
|
|
||||||
exports.Events = {
|
exports.Events = {
|
||||||
READY: 'ready',
|
READY: 'ready',
|
||||||
|
RESUME: 'resume',
|
||||||
GUILD_CREATE: 'guildCreate',
|
GUILD_CREATE: 'guildCreate',
|
||||||
GUILD_DELETE: 'guildDelete',
|
GUILD_DELETE: 'guildDelete',
|
||||||
GUILD_UPDATE: 'guildUpdate',
|
GUILD_UPDATE: 'guildUpdate',
|
||||||
@@ -320,6 +337,7 @@ exports.Events = {
|
|||||||
USER_UPDATE: 'userUpdate',
|
USER_UPDATE: 'userUpdate',
|
||||||
USER_NOTE_UPDATE: 'userNoteUpdate',
|
USER_NOTE_UPDATE: 'userNoteUpdate',
|
||||||
USER_SETTINGS_UPDATE: 'clientUserSettingsUpdate',
|
USER_SETTINGS_UPDATE: 'clientUserSettingsUpdate',
|
||||||
|
USER_GUILD_SETTINGS_UPDATE: 'clientUserGuildSettingsUpdate',
|
||||||
PRESENCE_UPDATE: 'presenceUpdate',
|
PRESENCE_UPDATE: 'presenceUpdate',
|
||||||
VOICE_STATE_UPDATE: 'voiceStateUpdate',
|
VOICE_STATE_UPDATE: 'voiceStateUpdate',
|
||||||
TYPING_START: 'typingStart',
|
TYPING_START: 'typingStart',
|
||||||
@@ -333,41 +351,41 @@ exports.Events = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
|
* The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
|
||||||
* - READY
|
* * READY
|
||||||
* - RESUMED
|
* * RESUMED
|
||||||
* - GUILD_SYNC
|
* * GUILD_SYNC
|
||||||
* - GUILD_CREATE
|
* * GUILD_CREATE
|
||||||
* - GUILD_DELETE
|
* * GUILD_DELETE
|
||||||
* - GUILD_UPDATE
|
* * GUILD_UPDATE
|
||||||
* - GUILD_MEMBER_ADD
|
* * GUILD_MEMBER_ADD
|
||||||
* - GUILD_MEMBER_REMOVE
|
* * GUILD_MEMBER_REMOVE
|
||||||
* - GUILD_MEMBER_UPDATE
|
* * GUILD_MEMBER_UPDATE
|
||||||
* - GUILD_MEMBERS_CHUNK
|
* * GUILD_MEMBERS_CHUNK
|
||||||
* - GUILD_ROLE_CREATE
|
* * GUILD_ROLE_CREATE
|
||||||
* - GUILD_ROLE_DELETE
|
* * GUILD_ROLE_DELETE
|
||||||
* - GUILD_ROLE_UPDATE
|
* * GUILD_ROLE_UPDATE
|
||||||
* - GUILD_BAN_ADD
|
* * GUILD_BAN_ADD
|
||||||
* - GUILD_BAN_REMOVE
|
* * GUILD_BAN_REMOVE
|
||||||
* - CHANNEL_CREATE
|
* * CHANNEL_CREATE
|
||||||
* - CHANNEL_DELETE
|
* * CHANNEL_DELETE
|
||||||
* - CHANNEL_UPDATE
|
* * CHANNEL_UPDATE
|
||||||
* - CHANNEL_PINS_UPDATE
|
* * CHANNEL_PINS_UPDATE
|
||||||
* - MESSAGE_CREATE
|
* * MESSAGE_CREATE
|
||||||
* - MESSAGE_DELETE
|
* * MESSAGE_DELETE
|
||||||
* - MESSAGE_UPDATE
|
* * MESSAGE_UPDATE
|
||||||
* - MESSAGE_DELETE_BULK
|
* * MESSAGE_DELETE_BULK
|
||||||
* - MESSAGE_REACTION_ADD
|
* * MESSAGE_REACTION_ADD
|
||||||
* - MESSAGE_REACTION_REMOVE
|
* * MESSAGE_REACTION_REMOVE
|
||||||
* - MESSAGE_REACTION_REMOVE_ALL
|
* * MESSAGE_REACTION_REMOVE_ALL
|
||||||
* - USER_UPDATE
|
* * USER_UPDATE
|
||||||
* - USER_NOTE_UPDATE
|
* * USER_NOTE_UPDATE
|
||||||
* - USER_SETTINGS_UPDATE
|
* * USER_SETTINGS_UPDATE
|
||||||
* - PRESENCE_UPDATE
|
* * PRESENCE_UPDATE
|
||||||
* - VOICE_STATE_UPDATE
|
* * VOICE_STATE_UPDATE
|
||||||
* - TYPING_START
|
* * TYPING_START
|
||||||
* - VOICE_SERVER_UPDATE
|
* * VOICE_SERVER_UPDATE
|
||||||
* - RELATIONSHIP_ADD
|
* * RELATIONSHIP_ADD
|
||||||
* - RELATIONSHIP_REMOVE
|
* * RELATIONSHIP_REMOVE
|
||||||
* @typedef {string} WSEventType
|
* @typedef {string} WSEventType
|
||||||
*/
|
*/
|
||||||
exports.WSEvents = {
|
exports.WSEvents = {
|
||||||
@@ -401,6 +419,7 @@ exports.WSEvents = {
|
|||||||
USER_UPDATE: 'USER_UPDATE',
|
USER_UPDATE: 'USER_UPDATE',
|
||||||
USER_NOTE_UPDATE: 'USER_NOTE_UPDATE',
|
USER_NOTE_UPDATE: 'USER_NOTE_UPDATE',
|
||||||
USER_SETTINGS_UPDATE: 'USER_SETTINGS_UPDATE',
|
USER_SETTINGS_UPDATE: 'USER_SETTINGS_UPDATE',
|
||||||
|
USER_GUILD_SETTINGS_UPDATE: 'USER_GUILD_SETTINGS_UPDATE',
|
||||||
PRESENCE_UPDATE: 'PRESENCE_UPDATE',
|
PRESENCE_UPDATE: 'PRESENCE_UPDATE',
|
||||||
VOICE_STATE_UPDATE: 'VOICE_STATE_UPDATE',
|
VOICE_STATE_UPDATE: 'VOICE_STATE_UPDATE',
|
||||||
TYPING_START: 'TYPING_START',
|
TYPING_START: 'TYPING_START',
|
||||||
@@ -409,6 +428,18 @@ exports.WSEvents = {
|
|||||||
RELATIONSHIP_REMOVE: 'RELATIONSHIP_REMOVE',
|
RELATIONSHIP_REMOVE: 'RELATIONSHIP_REMOVE',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a message, e.g. `DEFAULT`. Here are the available types:
|
||||||
|
* * DEFAULT
|
||||||
|
* * RECIPIENT_ADD
|
||||||
|
* * RECIPIENT_REMOVE
|
||||||
|
* * CALL
|
||||||
|
* * CHANNEL_NAME_CHANGE
|
||||||
|
* * CHANNEL_ICON_CHANGE
|
||||||
|
* * PINS_ADD
|
||||||
|
* * GUILD_MEMBER_JOIN
|
||||||
|
* @typedef {string} MessageType
|
||||||
|
*/
|
||||||
exports.MessageTypes = [
|
exports.MessageTypes = [
|
||||||
'DEFAULT',
|
'DEFAULT',
|
||||||
'RECIPIENT_ADD',
|
'RECIPIENT_ADD',
|
||||||
@@ -420,6 +451,21 @@ exports.MessageTypes = [
|
|||||||
'GUILD_MEMBER_JOIN',
|
'GUILD_MEMBER_JOIN',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a message notification setting. Here are the available types:
|
||||||
|
* * EVERYTHING
|
||||||
|
* * MENTIONS
|
||||||
|
* * NOTHING
|
||||||
|
* * INHERIT (only for GuildChannel)
|
||||||
|
* @typedef {string} MessageNotificationType
|
||||||
|
*/
|
||||||
|
exports.MessageNotificationTypes = [
|
||||||
|
'EVERYTHING',
|
||||||
|
'MENTIONS',
|
||||||
|
'NOTHING',
|
||||||
|
'INHERIT',
|
||||||
|
];
|
||||||
|
|
||||||
exports.DefaultAvatars = {
|
exports.DefaultAvatars = {
|
||||||
BLURPLE: '6debd47ed13483642cf09e832ed0bc1b',
|
BLURPLE: '6debd47ed13483642cf09e832ed0bc1b',
|
||||||
GREY: '322c936a8c8be1b803cd94861bdfa868',
|
GREY: '322c936a8c8be1b803cd94861bdfa868',
|
||||||
@@ -543,8 +589,8 @@ exports.UserSettingsMap = {
|
|||||||
|
|
||||||
explicit_content_filter: function explicitContentFilter(type) { // eslint-disable-line func-name-matching
|
explicit_content_filter: function explicitContentFilter(type) { // eslint-disable-line func-name-matching
|
||||||
/**
|
/**
|
||||||
* Safe direct messaging; force people's messages with images to be scanned before they are sent to you
|
* Safe direct messaging; force people's messages with images to be scanned before they are sent to you.
|
||||||
* one of `DISABLED`, `NON_FRIENDS`, `FRIENDS_AND_NON_FRIENDS`
|
* One of `DISABLED`, `NON_FRIENDS`, `FRIENDS_AND_NON_FRIENDS`
|
||||||
* @name ClientUserSettings#explicitContentFilter
|
* @name ClientUserSettings#explicitContentFilter
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
@@ -567,6 +613,58 @@ exports.UserSettingsMap = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.UserGuildSettingsMap = {
|
||||||
|
message_notifications: function messageNotifications(type) { // eslint-disable-line func-name-matching
|
||||||
|
/**
|
||||||
|
* The type of message that should notify you
|
||||||
|
* @name ClientUserGuildSettings#messageNotifications
|
||||||
|
* @type {MessageNotificationType}
|
||||||
|
*/
|
||||||
|
return exports.MessageNotificationTypes[type];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Whether to receive mobile push notifications
|
||||||
|
* @name ClientUserGuildSettings#mobilePush
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
mobile_push: 'mobilePush',
|
||||||
|
/**
|
||||||
|
* Whether the guild is muted
|
||||||
|
* @name ClientUserGuildSettings#muted
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
muted: 'muted',
|
||||||
|
/**
|
||||||
|
* Whether to suppress everyone mention
|
||||||
|
* @name ClientUserGuildSettings#suppressEveryone
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
suppress_everyone: 'suppressEveryone',
|
||||||
|
/**
|
||||||
|
* A collection containing all the channel overrides
|
||||||
|
* @name ClientUserGuildSettings#channelOverrides
|
||||||
|
* @type {Collection<ClientUserChannelOverride>}
|
||||||
|
*/
|
||||||
|
channel_overrides: 'channelOverrides',
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.UserChannelOverrideMap = {
|
||||||
|
message_notifications: function messageNotifications(type) { // eslint-disable-line func-name-matching
|
||||||
|
/**
|
||||||
|
* The type of message that should notify you
|
||||||
|
* @name ClientUserChannelOverride#messageNotifications
|
||||||
|
* @type {MessageNotificationType}
|
||||||
|
*/
|
||||||
|
return exports.MessageNotificationTypes[type];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Whether the channel is muted
|
||||||
|
* @name ClientUserChannelOverride#muted
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
muted: 'muted',
|
||||||
|
};
|
||||||
|
|
||||||
exports.Colors = {
|
exports.Colors = {
|
||||||
DEFAULT: 0x000000,
|
DEFAULT: 0x000000,
|
||||||
AQUA: 0x1ABC9C,
|
AQUA: 0x1ABC9C,
|
||||||
@@ -594,3 +692,96 @@ exports.Colors = {
|
|||||||
DARK_BUT_NOT_BLACK: 0x2C2F33,
|
DARK_BUT_NOT_BLACK: 0x2C2F33,
|
||||||
NOT_QUITE_BLACK: 0x23272A,
|
NOT_QUITE_BLACK: 0x23272A,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error encountered while performing an API request. Here are the potential errors:
|
||||||
|
* * UNKNOWN_ACCOUNT
|
||||||
|
* * UNKNOWN_APPLICATION
|
||||||
|
* * UNKNOWN_CHANNEL
|
||||||
|
* * UNKNOWN_GUILD
|
||||||
|
* * UNKNOWN_INTEGRATION
|
||||||
|
* * UNKNOWN_INVITE
|
||||||
|
* * UNKNOWN_MEMBER
|
||||||
|
* * UNKNOWN_MESSAGE
|
||||||
|
* * UNKNOWN_OVERWRITE
|
||||||
|
* * UNKNOWN_PROVIDER
|
||||||
|
* * UNKNOWN_ROLE
|
||||||
|
* * UNKNOWN_TOKEN
|
||||||
|
* * UNKNOWN_USER
|
||||||
|
* * UNKNOWN_EMOJI
|
||||||
|
* * BOT_PROHIBITED_ENDPOINT
|
||||||
|
* * BOT_ONLY_ENDPOINT
|
||||||
|
* * MAXIMUM_GUILDS
|
||||||
|
* * MAXIMUM_FRIENDS
|
||||||
|
* * MAXIMUM_PINS
|
||||||
|
* * MAXIMUM_ROLES
|
||||||
|
* * MAXIMUM_REACTIONS
|
||||||
|
* * UNAUTHORIZED
|
||||||
|
* * MISSING_ACCESS
|
||||||
|
* * INVALID_ACCOUNT_TYPE
|
||||||
|
* * CANNOT_EXECUTE_ON_DM
|
||||||
|
* * EMBED_DISABLED
|
||||||
|
* * CANNOT_EDIT_MESSAGE_BY_OTHER
|
||||||
|
* * CANNOT_SEND_EMPTY_MESSAGE
|
||||||
|
* * CANNOT_MESSAGE_USER
|
||||||
|
* * CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL
|
||||||
|
* * CHANNEL_VERIFICATION_LEVEL_TOO_HIGH
|
||||||
|
* * OAUTH2_APPLICATION_BOT_ABSENT
|
||||||
|
* * MAXIMUM_OAUTH2_APPLICATIONS
|
||||||
|
* * INVALID_OAUTH_STATE
|
||||||
|
* * MISSING_PERMISSIONS
|
||||||
|
* * INVALID_AUTHENTICATION_TOKEN
|
||||||
|
* * NOTE_TOO_LONG
|
||||||
|
* * INVALID_BULK_DELETE_QUANTITY
|
||||||
|
* * CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL
|
||||||
|
* * CANNOT_EXECUTE_ON_SYSTEM_MESSAGE
|
||||||
|
* * BULK_DELETE_MESSAGE_TOO_OLD
|
||||||
|
* * INVITE_ACCEPTED_TO_GUILD_NOT_CONTANING_BOT
|
||||||
|
* * REACTION_BLOCKED
|
||||||
|
* @typedef {string} APIError
|
||||||
|
*/
|
||||||
|
exports.APIErrors = {
|
||||||
|
UNKNOWN_ACCOUNT: 10001,
|
||||||
|
UNKNOWN_APPLICATION: 10002,
|
||||||
|
UNKNOWN_CHANNEL: 10003,
|
||||||
|
UNKNOWN_GUILD: 10004,
|
||||||
|
UNKNOWN_INTEGRATION: 10005,
|
||||||
|
UNKNOWN_INVITE: 10006,
|
||||||
|
UNKNOWN_MEMBER: 10007,
|
||||||
|
UNKNOWN_MESSAGE: 10008,
|
||||||
|
UNKNOWN_OVERWRITE: 10009,
|
||||||
|
UNKNOWN_PROVIDER: 10010,
|
||||||
|
UNKNOWN_ROLE: 10011,
|
||||||
|
UNKNOWN_TOKEN: 10012,
|
||||||
|
UNKNOWN_USER: 10013,
|
||||||
|
UNKNOWN_EMOJI: 10014,
|
||||||
|
BOT_PROHIBITED_ENDPOINT: 20001,
|
||||||
|
BOT_ONLY_ENDPOINT: 20002,
|
||||||
|
MAXIMUM_GUILDS: 30001,
|
||||||
|
MAXIMUM_FRIENDS: 30002,
|
||||||
|
MAXIMUM_PINS: 30003,
|
||||||
|
MAXIMUM_ROLES: 30005,
|
||||||
|
MAXIMUM_REACTIONS: 30010,
|
||||||
|
UNAUTHORIZED: 40001,
|
||||||
|
MISSING_ACCESS: 50001,
|
||||||
|
INVALID_ACCOUNT_TYPE: 50002,
|
||||||
|
CANNOT_EXECUTE_ON_DM: 50003,
|
||||||
|
EMBED_DISABLED: 50004,
|
||||||
|
CANNOT_EDIT_MESSAGE_BY_OTHER: 50005,
|
||||||
|
CANNOT_SEND_EMPTY_MESSAGE: 50006,
|
||||||
|
CANNOT_MESSAGE_USER: 50007,
|
||||||
|
CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: 50008,
|
||||||
|
CHANNEL_VERIFICATION_LEVEL_TOO_HIGH: 50009,
|
||||||
|
OAUTH2_APPLICATION_BOT_ABSENT: 50010,
|
||||||
|
MAXIMUM_OAUTH2_APPLICATIONS: 50011,
|
||||||
|
INVALID_OAUTH_STATE: 50012,
|
||||||
|
MISSING_PERMISSIONS: 50013,
|
||||||
|
INVALID_AUTHENTICATION_TOKEN: 50014,
|
||||||
|
NOTE_TOO_LONG: 50015,
|
||||||
|
INVALID_BULK_DELETE_QUANTITY: 50016,
|
||||||
|
CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019,
|
||||||
|
CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021,
|
||||||
|
BULK_DELETE_MESSAGE_TOO_OLD: 50034,
|
||||||
|
INVITE_ACCEPTED_TO_GUILD_NOT_CONTANING_BOT: 50036,
|
||||||
|
REACTION_BLOCKED: 90001,
|
||||||
|
};
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class Permissions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an object mapping permission name (like `READ_MESSAGES`) to a {@link boolean} indicating whether the
|
* Gets an object mapping permission name (like `VIEW_CHANNEL`) to a {@link boolean} indicating whether the
|
||||||
* permission is available.
|
* permission is available.
|
||||||
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
@@ -152,8 +152,8 @@ class Permissions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that can be resolved to give a permission number. This can be:
|
* Data that can be resolved to give a permission number. This can be:
|
||||||
* - A string (see {@link Permissions.flags})
|
* * A string (see {@link Permissions.FLAGS})
|
||||||
* - A permission number
|
* * A permission number
|
||||||
* @typedef {string|number} PermissionResolvable
|
* @typedef {string|number} PermissionResolvable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -180,7 +180,8 @@ class Permissions {
|
|||||||
* - `MANAGE_GUILD` (edit the guild information, region, etc.)
|
* - `MANAGE_GUILD` (edit the guild information, region, etc.)
|
||||||
* - `ADD_REACTIONS` (add new reactions to messages)
|
* - `ADD_REACTIONS` (add new reactions to messages)
|
||||||
* - `VIEW_AUDIT_LOG`
|
* - `VIEW_AUDIT_LOG`
|
||||||
* - `READ_MESSAGES`
|
* - `VIEW_CHANNEL`
|
||||||
|
* - `READ_MESSAGES` **(deprecated)**
|
||||||
* - `SEND_MESSAGES`
|
* - `SEND_MESSAGES`
|
||||||
* - `SEND_TTS_MESSAGES`
|
* - `SEND_TTS_MESSAGES`
|
||||||
* - `MANAGE_MESSAGES` (delete messages and reactions)
|
* - `MANAGE_MESSAGES` (delete messages and reactions)
|
||||||
@@ -215,6 +216,7 @@ Permissions.FLAGS = {
|
|||||||
ADD_REACTIONS: 1 << 6,
|
ADD_REACTIONS: 1 << 6,
|
||||||
VIEW_AUDIT_LOG: 1 << 7,
|
VIEW_AUDIT_LOG: 1 << 7,
|
||||||
|
|
||||||
|
VIEW_CHANNEL: 1 << 10,
|
||||||
READ_MESSAGES: 1 << 10,
|
READ_MESSAGES: 1 << 10,
|
||||||
SEND_MESSAGES: 1 << 11,
|
SEND_MESSAGES: 1 << 11,
|
||||||
SEND_TTS_MESSAGES: 1 << 12,
|
SEND_TTS_MESSAGES: 1 << 12,
|
||||||
@@ -268,8 +270,8 @@ Permissions.prototype.missingPermissions = util.deprecate(Permissions.prototype.
|
|||||||
'EvaluatedPermissions#missingPermissions is deprecated, use Permissions#missing instead');
|
'EvaluatedPermissions#missingPermissions is deprecated, use Permissions#missing instead');
|
||||||
Object.defineProperty(Permissions.prototype, 'member', {
|
Object.defineProperty(Permissions.prototype, 'member', {
|
||||||
get: util
|
get: util
|
||||||
.deprecate(Object.getOwnPropertyDescriptor(Permissions.prototype, 'member').get,
|
.deprecate(Object.getOwnPropertyDescriptor(Permissions.prototype, 'member').get,
|
||||||
'EvaluatedPermissions#member is deprecated'),
|
'EvaluatedPermissions#member is deprecated'),
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = Permissions;
|
module.exports = Permissions;
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ class Util {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses emoji info out of a string. The string must be one of:
|
* Parses emoji info out of a string. The string must be one of:
|
||||||
* - A UTF-8 emoji (no ID)
|
* * A UTF-8 emoji (no ID)
|
||||||
* - A URL-encoded UTF-8 emoji (no ID)
|
* * A URL-encoded UTF-8 emoji (no ID)
|
||||||
* - A Discord custom emoji (`<:name:id>`)
|
* * A Discord custom emoji (`<:name:id>`)
|
||||||
* @param {string} text Emoji string to parse
|
* @param {string} text Emoji string to parse
|
||||||
* @returns {Object} Object with `name` and `id` properties
|
* @returns {Object} Object with `name` and `id` properties
|
||||||
* @private
|
* @private
|
||||||
|
|||||||
156
test/voice.js
156
test/voice.js
@@ -1,78 +1,78 @@
|
|||||||
/* eslint no-console: 0 */
|
/* eslint no-console: 0 */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Discord = require('../');
|
const Discord = require('../');
|
||||||
const ytdl = require('ytdl-core');
|
const ytdl = require('ytdl-core');
|
||||||
|
|
||||||
const client = new Discord.Client({ fetchAllMembers: false, apiRequestMethod: 'sequential' });
|
const client = new Discord.Client({ fetchAllMembers: false, apiRequestMethod: 'sequential' });
|
||||||
|
|
||||||
const auth = require('./auth.json');
|
const auth = require('./auth.json');
|
||||||
|
|
||||||
client.login(auth.token).then(() => console.log('logged')).catch(console.error);
|
client.login(auth.token).then(() => console.log('logged')).catch(console.error);
|
||||||
|
|
||||||
const connections = new Map();
|
const connections = new Map();
|
||||||
|
|
||||||
let broadcast;
|
let broadcast;
|
||||||
|
|
||||||
client.on('message', m => {
|
client.on('message', m => {
|
||||||
if (!m.guild) return;
|
if (!m.guild) return;
|
||||||
if (m.content.startsWith('/join')) {
|
if (m.content.startsWith('/join')) {
|
||||||
const channel = m.guild.channels.get(m.content.split(' ')[1]) || m.member.voiceChannel;
|
const channel = m.guild.channels.get(m.content.split(' ')[1]) || m.member.voiceChannel;
|
||||||
if (channel && channel.type === 'voice') {
|
if (channel && channel.type === 'voice') {
|
||||||
channel.join().then(conn => {
|
channel.join().then(conn => {
|
||||||
conn.player.on('error', (...e) => console.log('player', ...e));
|
conn.player.on('error', (...e) => console.log('player', ...e));
|
||||||
if (!connections.has(m.guild.id)) connections.set(m.guild.id, { conn, queue: [] });
|
if (!connections.has(m.guild.id)) connections.set(m.guild.id, { conn, queue: [] });
|
||||||
m.reply('ok!');
|
m.reply('ok!');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
m.reply('Specify a voice channel!');
|
m.reply('Specify a voice channel!');
|
||||||
}
|
}
|
||||||
} else if (m.content.startsWith('/play')) {
|
} else if (m.content.startsWith('/play')) {
|
||||||
if (connections.has(m.guild.id)) {
|
if (connections.has(m.guild.id)) {
|
||||||
const connData = connections.get(m.guild.id);
|
const connData = connections.get(m.guild.id);
|
||||||
const queue = connData.queue;
|
const queue = connData.queue;
|
||||||
const url = m.content.split(' ').slice(1).join(' ')
|
const url = m.content.split(' ').slice(1).join(' ')
|
||||||
.replace(/</g, '')
|
.replace(/</g, '')
|
||||||
.replace(/>/g, '');
|
.replace(/>/g, '');
|
||||||
queue.push({ url, m });
|
queue.push({ url, m });
|
||||||
if (queue.length > 1) {
|
if (queue.length > 1) {
|
||||||
m.reply(`OK, that's going to play after ${queue.length - 1} songs`);
|
m.reply(`OK, that's going to play after ${queue.length - 1} songs`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
doQueue(connData);
|
doQueue(connData);
|
||||||
}
|
}
|
||||||
} else if (m.content.startsWith('/skip')) {
|
} else if (m.content.startsWith('/skip')) {
|
||||||
if (connections.has(m.guild.id)) {
|
if (connections.has(m.guild.id)) {
|
||||||
const connData = connections.get(m.guild.id);
|
const connData = connections.get(m.guild.id);
|
||||||
if (connData.dispatcher) {
|
if (connData.dispatcher) {
|
||||||
connData.dispatcher.end();
|
connData.dispatcher.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (m.content.startsWith('#eval') && m.author.id === '66564597481480192') {
|
} else if (m.content.startsWith('#eval') && m.author.id === '66564597481480192') {
|
||||||
try {
|
try {
|
||||||
const com = eval(m.content.split(' ').slice(1).join(' '));
|
const com = eval(m.content.split(' ').slice(1).join(' '));
|
||||||
m.channel.sendMessage(`\`\`\`\n${com}\`\`\``);
|
m.channel.sendMessage(`\`\`\`\n${com}\`\`\``);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
m.channel.sendMessage(`\`\`\`\n${e}\`\`\``);
|
m.channel.sendMessage(`\`\`\`\n${e}\`\`\``);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function doQueue(connData) {
|
function doQueue(connData) {
|
||||||
const conn = connData.conn;
|
const conn = connData.conn;
|
||||||
const queue = connData.queue;
|
const queue = connData.queue;
|
||||||
const item = queue[0];
|
const item = queue[0];
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
const stream = ytdl(item.url, { filter: 'audioonly' }, { passes: 3 });
|
const stream = ytdl(item.url, { filter: 'audioonly' }, { passes: 3 });
|
||||||
const dispatcher = conn.playStream(stream);
|
const dispatcher = conn.playStream(stream);
|
||||||
stream.on('info', info => {
|
stream.on('info', info => {
|
||||||
item.m.reply(`OK, playing **${info.title}**`);
|
item.m.reply(`OK, playing **${info.title}**`);
|
||||||
});
|
});
|
||||||
dispatcher.on('end', () => {
|
dispatcher.on('end', () => {
|
||||||
queue.shift();
|
queue.shift();
|
||||||
doQueue(connData);
|
doQueue(connData);
|
||||||
});
|
});
|
||||||
dispatcher.on('error', (...e) => console.log('dispatcher', ...e));
|
dispatcher.on('error', (...e) => console.log('dispatcher', ...e));
|
||||||
connData.dispatcher = dispatcher;
|
connData.dispatcher = dispatcher;
|
||||||
}
|
}
|
||||||
|
|||||||
2
typings
2
typings
Submodule typings updated: b500eb2331...697fc933de
@@ -5,19 +5,26 @@
|
|||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const createVariants = require('parallel-webpack').createVariants;
|
const createVariants = require('parallel-webpack').createVariants;
|
||||||
|
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||||
const version = require('./package.json').version;
|
const version = require('./package.json').version;
|
||||||
|
|
||||||
const createConfig = options => {
|
const createConfig = options => {
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new webpack.DefinePlugin({ 'global.GENTLY': false }),
|
new webpack.DefinePlugin({ 'global.GENTLY': false }),
|
||||||
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
__DISCORD_WEBPACK__: '"true"',
|
||||||
|
},
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (options.minify) plugins.push(new webpack.optimize.UglifyJsPlugin({ minimize: true }));
|
if (options.minify) plugins.push(new UglifyJSPlugin({ uglifyOptions: { output: { comments: false } } }));
|
||||||
|
|
||||||
const filename = `./webpack/discord${process.env.VERSIONED === 'false' ? '' : '.' + version}${options.minify ? '.min' : ''}.js`; // eslint-disable-line
|
const filename = `./webpack/discord${process.env.VERSIONED === 'false' ? '' : '.' + version}${options.minify ? '.min' : ''}.js`; // eslint-disable-line
|
||||||
|
|
||||||
return {
|
return {
|
||||||
entry: './src/index.js',
|
entry: './browser.js',
|
||||||
output: {
|
output: {
|
||||||
path: __dirname,
|
path: __dirname,
|
||||||
filename,
|
filename,
|
||||||
|
|||||||
Reference in New Issue
Block a user