discord.js 15.0.0-dev.1745539999-8e4e319c2 → 15.0.0-dev.1745755498-d32aacd14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/client/Client.js +14 -0
- package/src/client/actions/Action.js +4 -0
- package/src/client/actions/ActionsManager.js +1 -0
- package/src/client/actions/GuildSoundboardSoundDelete.js +29 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +24 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +18 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +20 -0
- package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +24 -0
- package/src/client/websocket/handlers/index.js +5 -0
- package/src/errors/ErrorCodes.js +5 -0
- package/src/errors/Messages.js +3 -0
- package/src/index.js +2 -0
- package/src/managers/GuildManager.js +67 -1
- package/src/managers/GuildSoundboardSoundManager.js +192 -0
- package/src/structures/Guild.js +7 -0
- package/src/structures/GuildAuditLogsEntry.js +4 -5
- package/src/structures/SoundboardSound.js +204 -0
- package/src/structures/Sticker.js +1 -1
- package/src/structures/VoiceChannel.js +21 -1
- package/src/structures/VoiceChannelEffect.js +9 -0
- package/src/util/DataResolver.js +5 -4
- package/src/util/Events.js +10 -0
- package/src/util/Partials.js +2 -0
- package/typings/index.d.mts +88 -1
- package/typings/index.d.ts +88 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "discord.js",
|
|
4
|
-
"version": "15.0.0-dev.
|
|
4
|
+
"version": "15.0.0-dev.1745755498-d32aacd14",
|
|
5
5
|
"description": "A powerful library for interacting with the Discord API",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"types": "./typings/index.d.ts",
|
|
@@ -57,13 +57,14 @@
|
|
|
57
57
|
"discord-api-types": "^0.38.1",
|
|
58
58
|
"fast-deep-equal": "3.1.3",
|
|
59
59
|
"lodash.snakecase": "4.1.1",
|
|
60
|
+
"magic-bytes.js": "^1.10.0",
|
|
60
61
|
"tslib": "^2.8.1",
|
|
61
62
|
"undici": "7.8.0",
|
|
62
|
-
"@discordjs/
|
|
63
|
+
"@discordjs/collection": "^2.1.1",
|
|
63
64
|
"@discordjs/formatters": "^0.5.0",
|
|
64
65
|
"@discordjs/rest": "^2.4.0",
|
|
66
|
+
"@discordjs/builders": "^1.9.0",
|
|
65
67
|
"@discordjs/util": "^1.1.1",
|
|
66
|
-
"@discordjs/collection": "^2.1.1",
|
|
67
68
|
"@discordjs/ws": "^2.0.0"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
package/src/client/Client.js
CHANGED
|
@@ -19,6 +19,7 @@ const { ClientPresence } = require('../structures/ClientPresence.js');
|
|
|
19
19
|
const { GuildPreview } = require('../structures/GuildPreview.js');
|
|
20
20
|
const { GuildTemplate } = require('../structures/GuildTemplate.js');
|
|
21
21
|
const { Invite } = require('../structures/Invite.js');
|
|
22
|
+
const { SoundboardSound } = require('../structures/SoundboardSound.js');
|
|
22
23
|
const { Sticker } = require('../structures/Sticker.js');
|
|
23
24
|
const { StickerPack } = require('../structures/StickerPack.js');
|
|
24
25
|
const { VoiceRegion } = require('../structures/VoiceRegion.js');
|
|
@@ -536,6 +537,19 @@ class Client extends BaseClient {
|
|
|
536
537
|
return new Collection(data.sticker_packs.map(stickerPack => [stickerPack.id, new StickerPack(this, stickerPack)]));
|
|
537
538
|
}
|
|
538
539
|
|
|
540
|
+
/**
|
|
541
|
+
* Obtains the list of default soundboard sounds.
|
|
542
|
+
* @returns {Promise<Collection<string, SoundboardSound>>}
|
|
543
|
+
* @example
|
|
544
|
+
* client.fetchDefaultSoundboardSounds()
|
|
545
|
+
* .then(sounds => console.log(`Available soundboard sounds are: ${sounds.map(sound => sound.name).join(', ')}`))
|
|
546
|
+
* .catch(console.error);
|
|
547
|
+
*/
|
|
548
|
+
async fetchDefaultSoundboardSounds() {
|
|
549
|
+
const data = await this.rest.get(Routes.soundboardDefaultSounds());
|
|
550
|
+
return new Collection(data.map(sound => [sound.sound_id, new SoundboardSound(this, sound)]));
|
|
551
|
+
}
|
|
552
|
+
|
|
539
553
|
/**
|
|
540
554
|
* Obtains a guild preview from Discord, available for all guilds the bot is in and all Discoverable guilds.
|
|
541
555
|
* @param {GuildResolvable} guild The guild to fetch the preview for
|
|
@@ -131,6 +131,10 @@ class Action {
|
|
|
131
131
|
return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
getSoundboardSound(data, guild) {
|
|
135
|
+
return this.getPayload(data, guild.soundboardSounds, data.sound_id, Partials.SoundboardSound);
|
|
136
|
+
}
|
|
137
|
+
|
|
134
138
|
spreadInjectedData(data) {
|
|
135
139
|
return Object.fromEntries(Object.getOwnPropertySymbols(data).map(symbol => [symbol, data[symbol]]));
|
|
136
140
|
}
|
|
@@ -27,6 +27,7 @@ class ActionsManager {
|
|
|
27
27
|
this.register(require('./GuildScheduledEventDelete.js').GuildScheduledEventDeleteAction);
|
|
28
28
|
this.register(require('./GuildScheduledEventUserAdd.js').GuildScheduledEventUserAddAction);
|
|
29
29
|
this.register(require('./GuildScheduledEventUserRemove.js').GuildScheduledEventUserRemoveAction);
|
|
30
|
+
this.register(require('./GuildSoundboardSoundDelete.js').GuildSoundboardSoundDeleteAction);
|
|
30
31
|
this.register(require('./GuildStickerCreate.js').GuildStickerCreateAction);
|
|
31
32
|
this.register(require('./GuildStickerDelete.js').GuildStickerDeleteAction);
|
|
32
33
|
this.register(require('./GuildStickerUpdate.js').GuildStickerUpdateAction);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Action } = require('./Action.js');
|
|
4
|
+
const { Events } = require('../../util/Events.js');
|
|
5
|
+
|
|
6
|
+
class GuildSoundboardSoundDeleteAction extends Action {
|
|
7
|
+
handle(data) {
|
|
8
|
+
const guild = this.client.guilds.cache.get(data.guild_id);
|
|
9
|
+
|
|
10
|
+
if (!guild) return {};
|
|
11
|
+
|
|
12
|
+
const soundboardSound = this.getSoundboardSound(data, guild);
|
|
13
|
+
|
|
14
|
+
if (soundboardSound) {
|
|
15
|
+
guild.soundboardSounds.cache.delete(soundboardSound.soundId);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emitted whenever a soundboard sound is deleted in a guild.
|
|
19
|
+
* @event Client#guildSoundboardSoundDelete
|
|
20
|
+
* @param {SoundboardSound} soundboardSound The soundboard sound that was deleted
|
|
21
|
+
*/
|
|
22
|
+
this.client.emit(Events.GuildSoundboardSoundDelete, soundboardSound);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { soundboardSound };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.GuildSoundboardSoundDeleteAction = GuildSoundboardSoundDeleteAction;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Collection } = require('@discordjs/collection');
|
|
4
|
+
const { Events } = require('../../../util/Events.js');
|
|
5
|
+
|
|
6
|
+
module.exports = (client, { d: data }) => {
|
|
7
|
+
const guild = client.guilds.cache.get(data.guild_id);
|
|
8
|
+
|
|
9
|
+
if (!guild) return;
|
|
10
|
+
|
|
11
|
+
const soundboardSounds = new Collection();
|
|
12
|
+
|
|
13
|
+
for (const soundboardSound of data.soundboard_sounds) {
|
|
14
|
+
soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emitted whenever multiple guild soundboard sounds are updated.
|
|
19
|
+
* @event Client#guildSoundboardSoundsUpdate
|
|
20
|
+
* @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The updated soundboard sounds
|
|
21
|
+
* @param {Guild} guild The guild that the soundboard sounds are from
|
|
22
|
+
*/
|
|
23
|
+
client.emit(Events.GuildSoundboardSoundsUpdate, soundboardSounds, guild);
|
|
24
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Events } = require('../../../util/Events.js');
|
|
4
|
+
|
|
5
|
+
module.exports = (client, { d: data }) => {
|
|
6
|
+
const guild = client.guilds.cache.get(data.guild_id);
|
|
7
|
+
|
|
8
|
+
if (!guild) return;
|
|
9
|
+
|
|
10
|
+
const soundboardSound = guild.soundboardSounds._add(data);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Emitted whenever a guild soundboard sound is created.
|
|
14
|
+
* @event Client#guildSoundboardSoundCreate
|
|
15
|
+
* @param {SoundboardSound} soundboardSound The created guild soundboard sound
|
|
16
|
+
*/
|
|
17
|
+
client.emit(Events.GuildSoundboardSoundCreate, soundboardSound);
|
|
18
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Events } = require('../../../util/Events.js');
|
|
4
|
+
|
|
5
|
+
module.exports = (client, { d: data }) => {
|
|
6
|
+
const guild = client.guilds.cache.get(data.guild_id);
|
|
7
|
+
|
|
8
|
+
if (!guild) return;
|
|
9
|
+
|
|
10
|
+
const oldGuildSoundboardSound = guild.soundboardSounds.cache.get(data.sound_id)?._clone() ?? null;
|
|
11
|
+
const newGuildSoundboardSound = guild.soundboardSounds._add(data);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Emitted whenever a guild soundboard sound is updated.
|
|
15
|
+
* @event Client#guildSoundboardSoundUpdate
|
|
16
|
+
* @param {?SoundboardSound} oldGuildSoundboardSound The guild soundboard sound before the update
|
|
17
|
+
* @param {SoundboardSound} newGuildSoundboardSound The guild soundboard sound after the update
|
|
18
|
+
*/
|
|
19
|
+
client.emit(Events.GuildSoundboardSoundUpdate, oldGuildSoundboardSound, newGuildSoundboardSound);
|
|
20
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Collection } = require('@discordjs/collection');
|
|
4
|
+
const { Events } = require('../../../util/Events.js');
|
|
5
|
+
|
|
6
|
+
module.exports = (client, { d: data }) => {
|
|
7
|
+
const guild = client.guilds.cache.get(data.guild_id);
|
|
8
|
+
|
|
9
|
+
if (!guild) return;
|
|
10
|
+
|
|
11
|
+
const soundboardSounds = new Collection();
|
|
12
|
+
|
|
13
|
+
for (const soundboardSound of data.soundboard_sounds) {
|
|
14
|
+
soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emitted whenever soundboard sounds are received (all soundboard sounds come from the same guild).
|
|
19
|
+
* @event Client#soundboardSounds
|
|
20
|
+
* @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The sounds received
|
|
21
|
+
* @param {Guild} guild The guild that the soundboard sounds are from
|
|
22
|
+
*/
|
|
23
|
+
client.emit(Events.SoundboardSounds, soundboardSounds, guild);
|
|
24
|
+
};
|
|
@@ -32,6 +32,10 @@ const PacketHandlers = Object.fromEntries([
|
|
|
32
32
|
['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE.js')],
|
|
33
33
|
['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD.js')],
|
|
34
34
|
['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE.js')],
|
|
35
|
+
['GUILD_SOUNDBOARD_SOUNDS_UPDATE', require('./GUILD_SOUNDBOARD_SOUNDS_UPDATE.js')],
|
|
36
|
+
['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE.js')],
|
|
37
|
+
['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE.js')],
|
|
38
|
+
['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE.js')],
|
|
35
39
|
['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE.js')],
|
|
36
40
|
['GUILD_UPDATE', require('./GUILD_UPDATE.js')],
|
|
37
41
|
['INTERACTION_CREATE', require('./INTERACTION_CREATE.js')],
|
|
@@ -49,6 +53,7 @@ const PacketHandlers = Object.fromEntries([
|
|
|
49
53
|
['MESSAGE_UPDATE', require('./MESSAGE_UPDATE.js')],
|
|
50
54
|
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE.js')],
|
|
51
55
|
['READY', require('./READY.js')],
|
|
56
|
+
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS.js')],
|
|
52
57
|
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE.js')],
|
|
53
58
|
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE.js')],
|
|
54
59
|
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE.js')],
|
package/src/errors/ErrorCodes.js
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
* @property {'GuildChannelUnowned'} GuildChannelUnowned
|
|
62
62
|
* @property {'GuildOwned'} GuildOwned
|
|
63
63
|
* @property {'GuildMembersTimeout'} GuildMembersTimeout
|
|
64
|
+
* @property {'GuildSoundboardSoundsTimeout'} GuildSoundboardSoundsTimeout
|
|
64
65
|
* @property {'GuildUncachedMe'} GuildUncachedMe
|
|
65
66
|
* @property {'ChannelNotCached'} ChannelNotCached
|
|
66
67
|
* @property {'StageChannelResolve'} StageChannelResolve
|
|
@@ -85,6 +86,8 @@
|
|
|
85
86
|
* @property {'EmojiManaged'} EmojiManaged
|
|
86
87
|
* @property {'MissingManageGuildExpressionsPermission'} MissingManageGuildExpressionsPermission
|
|
87
88
|
*
|
|
89
|
+
|
|
90
|
+
* @property {'NotGuildSoundboardSound'} NotGuildSoundboardSound
|
|
88
91
|
* @property {'NotGuildSticker'} NotGuildSticker
|
|
89
92
|
|
|
90
93
|
* @property {'ReactionResolveUser'} ReactionResolveUser
|
|
@@ -193,6 +196,7 @@ const keys = [
|
|
|
193
196
|
'GuildChannelUnowned',
|
|
194
197
|
'GuildOwned',
|
|
195
198
|
'GuildMembersTimeout',
|
|
199
|
+
'GuildSoundboardSoundsTimeout',
|
|
196
200
|
'GuildUncachedMe',
|
|
197
201
|
'ChannelNotCached',
|
|
198
202
|
'StageChannelResolve',
|
|
@@ -217,6 +221,7 @@ const keys = [
|
|
|
217
221
|
'EmojiManaged',
|
|
218
222
|
'MissingManageGuildExpressionsPermission',
|
|
219
223
|
|
|
224
|
+
'NotGuildSoundboardSound',
|
|
220
225
|
'NotGuildSticker',
|
|
221
226
|
|
|
222
227
|
'ReactionResolveUser',
|
package/src/errors/Messages.js
CHANGED
|
@@ -66,6 +66,7 @@ const Messages = {
|
|
|
66
66
|
[ErrorCodes.GuildChannelUnowned]: "The fetched channel does not belong to this manager's guild.",
|
|
67
67
|
[ErrorCodes.GuildOwned]: 'Guild is owned by the client.',
|
|
68
68
|
[ErrorCodes.GuildMembersTimeout]: "Members didn't arrive in time.",
|
|
69
|
+
[ErrorCodes.GuildSoundboardSoundsTimeout]: "Soundboard sounds didn't arrive in time.",
|
|
69
70
|
[ErrorCodes.GuildUncachedMe]: 'The client user as a member of this guild is uncached.',
|
|
70
71
|
[ErrorCodes.ChannelNotCached]: 'Could not find the channel where this message came from in the cache!',
|
|
71
72
|
[ErrorCodes.StageChannelResolve]: 'Could not resolve channel to a stage channel.',
|
|
@@ -91,6 +92,8 @@ const Messages = {
|
|
|
91
92
|
[ErrorCodes.MissingManageGuildExpressionsPermission]: guild =>
|
|
92
93
|
`Client must have Manage Guild Expressions permission in guild ${guild} to see emoji authors.`,
|
|
93
94
|
|
|
95
|
+
[ErrorCodes.NotGuildSoundboardSound]: action =>
|
|
96
|
+
`Soundboard sound is a default (non-guild) soundboard sound and can't be ${action}.`,
|
|
94
97
|
[ErrorCodes.NotGuildSticker]: 'Sticker is a standard (non-guild) sticker and has no author.',
|
|
95
98
|
|
|
96
99
|
[ErrorCodes.ReactionResolveUser]: "Couldn't resolve the user id to remove from the reaction.",
|
package/src/index.js
CHANGED
|
@@ -74,6 +74,7 @@ exports.GuildMemberManager = require('./managers/GuildMemberManager.js').GuildMe
|
|
|
74
74
|
exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager.js').GuildMemberRoleManager;
|
|
75
75
|
exports.GuildMessageManager = require('./managers/GuildMessageManager.js').GuildMessageManager;
|
|
76
76
|
exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager.js').GuildScheduledEventManager;
|
|
77
|
+
exports.GuildSoundboardSoundManager = require('./managers/GuildSoundboardSoundManager.js').GuildSoundboardSoundManager;
|
|
77
78
|
exports.GuildStickerManager = require('./managers/GuildStickerManager.js').GuildStickerManager;
|
|
78
79
|
exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager.js').GuildTextThreadManager;
|
|
79
80
|
exports.MessageManager = require('./managers/MessageManager.js').MessageManager;
|
|
@@ -196,6 +197,7 @@ exports.Role = require('./structures/Role.js').Role;
|
|
|
196
197
|
exports.RoleSelectMenuComponent = require('./structures/RoleSelectMenuComponent.js').RoleSelectMenuComponent;
|
|
197
198
|
exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteraction.js').RoleSelectMenuInteraction;
|
|
198
199
|
exports.SKU = require('./structures/SKU.js').SKU;
|
|
200
|
+
exports.SoundboardSound = require('./structures/SoundboardSound.js').SoundboardSound;
|
|
199
201
|
exports.StageChannel = require('./structures/StageChannel.js').StageChannel;
|
|
200
202
|
exports.StageInstance = require('./structures/StageInstance.js').StageInstance;
|
|
201
203
|
exports.Sticker = require('./structures/Sticker.js').Sticker;
|
|
@@ -4,8 +4,9 @@ const process = require('node:process');
|
|
|
4
4
|
const { setTimeout, clearTimeout } = require('node:timers');
|
|
5
5
|
const { Collection } = require('@discordjs/collection');
|
|
6
6
|
const { makeURLSearchParams } = require('@discordjs/rest');
|
|
7
|
-
const { Routes, RouteBases } = require('discord-api-types/v10');
|
|
7
|
+
const { GatewayOpcodes, Routes, RouteBases } = require('discord-api-types/v10');
|
|
8
8
|
const { CachedManager } = require('./CachedManager.js');
|
|
9
|
+
const { DiscordjsError, ErrorCodes } = require('../errors/index.js');
|
|
9
10
|
const { ShardClientUtil } = require('../sharding/ShardClientUtil.js');
|
|
10
11
|
const { Guild } = require('../structures/Guild.js');
|
|
11
12
|
const { GuildChannel } = require('../structures/GuildChannel.js');
|
|
@@ -282,6 +283,71 @@ class GuildManager extends CachedManager {
|
|
|
282
283
|
return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection());
|
|
283
284
|
}
|
|
284
285
|
|
|
286
|
+
/**
|
|
287
|
+
* @typedef {Object} FetchSoundboardSoundsOptions
|
|
288
|
+
* @param {Snowflake[]} guildIds The ids of the guilds to fetch soundboard sounds for
|
|
289
|
+
* @param {number} [time=10_000] The timeout for receipt of the soundboard sounds
|
|
290
|
+
*/
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Fetches soundboard sounds for the specified guilds.
|
|
294
|
+
* @param {FetchSoundboardSoundsOptions} options The options for fetching soundboard sounds
|
|
295
|
+
* @returns {Promise<Collection<Snowflake, Collection<Snowflake, SoundboardSound>>>}
|
|
296
|
+
* @example
|
|
297
|
+
* // Fetch soundboard sounds for multiple guilds
|
|
298
|
+
* const soundboardSounds = await client.guilds.fetchSoundboardSounds({
|
|
299
|
+
* guildIds: ['123456789012345678', '987654321098765432'],
|
|
300
|
+
* })
|
|
301
|
+
*
|
|
302
|
+
* console.log(soundboardSounds.get('123456789012345678'));
|
|
303
|
+
*/
|
|
304
|
+
async fetchSoundboardSounds({ guildIds, time = 10_000 }) {
|
|
305
|
+
const shardCount = await this.client.ws.getShardCount();
|
|
306
|
+
const shardIds = Map.groupBy(guildIds, guildId => ShardClientUtil.shardIdForGuildId(guildId, shardCount));
|
|
307
|
+
|
|
308
|
+
for (const [shardId, shardGuildIds] of shardIds) {
|
|
309
|
+
this.client.ws.send(shardId, {
|
|
310
|
+
op: GatewayOpcodes.RequestSoundboardSounds,
|
|
311
|
+
d: {
|
|
312
|
+
guild_ids: shardGuildIds,
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return new Promise((resolve, reject) => {
|
|
318
|
+
const remainingGuildIds = new Set(guildIds);
|
|
319
|
+
|
|
320
|
+
const fetchedSoundboardSounds = new Collection();
|
|
321
|
+
|
|
322
|
+
const handler = (soundboardSounds, guild) => {
|
|
323
|
+
timeout.refresh();
|
|
324
|
+
|
|
325
|
+
if (!remainingGuildIds.has(guild.id)) return;
|
|
326
|
+
|
|
327
|
+
fetchedSoundboardSounds.set(guild.id, soundboardSounds);
|
|
328
|
+
|
|
329
|
+
remainingGuildIds.delete(guild.id);
|
|
330
|
+
|
|
331
|
+
if (remainingGuildIds.size === 0) {
|
|
332
|
+
clearTimeout(timeout);
|
|
333
|
+
this.client.removeListener(Events.SoundboardSounds, handler);
|
|
334
|
+
this.client.decrementMaxListeners();
|
|
335
|
+
|
|
336
|
+
resolve(fetchedSoundboardSounds);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const timeout = setTimeout(() => {
|
|
341
|
+
this.client.removeListener(Events.SoundboardSounds, handler);
|
|
342
|
+
this.client.decrementMaxListeners();
|
|
343
|
+
reject(new DiscordjsError(ErrorCodes.GuildSoundboardSoundsTimeout));
|
|
344
|
+
}, time).unref();
|
|
345
|
+
|
|
346
|
+
this.client.incrementMaxListeners();
|
|
347
|
+
this.client.on(Events.SoundboardSounds, handler);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
285
351
|
/**
|
|
286
352
|
* Options used to set incident actions. Supplying `null` to any option will disable the action.
|
|
287
353
|
* @typedef {Object} IncidentActionsEditOptions
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Collection } = require('@discordjs/collection');
|
|
4
|
+
const { lazy } = require('@discordjs/util');
|
|
5
|
+
const { Routes } = require('discord-api-types/v10');
|
|
6
|
+
const { CachedManager } = require('./CachedManager.js');
|
|
7
|
+
const { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
|
8
|
+
const { SoundboardSound } = require('../structures/SoundboardSound.js');
|
|
9
|
+
const { resolveBase64, resolveFile } = require('../util/DataResolver.js');
|
|
10
|
+
|
|
11
|
+
const fileTypeMime = lazy(() => require('magic-bytes.js').filetypemime);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Manages API methods for Soundboard Sounds and stores their cache.
|
|
15
|
+
* @extends {CachedManager}
|
|
16
|
+
*/
|
|
17
|
+
class GuildSoundboardSoundManager extends CachedManager {
|
|
18
|
+
constructor(guild, iterable) {
|
|
19
|
+
super(guild.client, SoundboardSound, iterable);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The guild this manager belongs to
|
|
23
|
+
* @type {Guild}
|
|
24
|
+
*/
|
|
25
|
+
this.guild = guild;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The cache of Soundboard Sounds
|
|
30
|
+
* @type {Collection<Snowflake, SoundboardSound>}
|
|
31
|
+
* @name GuildSoundboardSoundManager#cache
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
_add(data, cache) {
|
|
35
|
+
return super._add(data, cache, { extras: [this.guild], id: data.sound_id });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Data that resolves to give a SoundboardSound object. This can be:
|
|
40
|
+
* * A SoundboardSound object
|
|
41
|
+
* * A Snowflake
|
|
42
|
+
* @typedef {SoundboardSound|Snowflake} SoundboardSoundResolvable
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a SoundboardSoundResolvable to a SoundboardSound object.
|
|
47
|
+
* @method resolve
|
|
48
|
+
* @memberof GuildSoundboardSoundManager
|
|
49
|
+
* @instance
|
|
50
|
+
* @param {SoundboardSoundResolvable} soundboardSound The SoundboardSound resolvable to identify
|
|
51
|
+
* @returns {?SoundboardSound}
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolves a {@link SoundboardSoundResolvable} to a {@link SoundboardSound} id.
|
|
56
|
+
* @param {SoundboardSoundResolvable} soundboardSound The soundboard sound resolvable to resolve
|
|
57
|
+
* @returns {?Snowflake}
|
|
58
|
+
*/
|
|
59
|
+
resolveId(soundboardSound) {
|
|
60
|
+
if (soundboardSound instanceof this.holds) return soundboardSound.soundId;
|
|
61
|
+
if (typeof soundboardSound === 'string') return soundboardSound;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Options used to create a soundboard sound in a guild.
|
|
67
|
+
* @typedef {Object} GuildSoundboardSoundCreateOptions
|
|
68
|
+
* @property {BufferResolvable|Stream} file The file for the soundboard sound
|
|
69
|
+
* @property {string} name The name for the soundboard sound
|
|
70
|
+
* @property {string} [contentType] The content type for the soundboard sound file
|
|
71
|
+
* @property {number} [volume] The volume (a double) for the soundboard sound, from 0 (inclusive) to 1. Defaults to 1
|
|
72
|
+
* @property {Snowflake} [emojiId] The emoji id for the soundboard sound
|
|
73
|
+
* @property {string} [emojiName] The emoji name for the soundboard sound
|
|
74
|
+
* @property {string} [reason] The reason for creating the soundboard sound
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Creates a new guild soundboard sound.
|
|
79
|
+
* @param {GuildSoundboardSoundCreateOptions} options Options for creating a guild soundboard sound
|
|
80
|
+
* @returns {Promise<SoundboardSound>} The created soundboard sound
|
|
81
|
+
* @example
|
|
82
|
+
* // Create a new soundboard sound from a file on your computer
|
|
83
|
+
* guild.soundboardSounds.create({ file: './sound.mp3', name: 'sound' })
|
|
84
|
+
* .then(sound => console.log(`Created new soundboard sound with name ${sound.name}!`))
|
|
85
|
+
* .catch(console.error);
|
|
86
|
+
*/
|
|
87
|
+
async create({ contentType, emojiId, emojiName, file, name, reason, volume }) {
|
|
88
|
+
const resolvedFile = await resolveFile(file);
|
|
89
|
+
|
|
90
|
+
const resolvedContentType = contentType ?? resolvedFile.contentType ?? fileTypeMime()(resolvedFile.data)[0];
|
|
91
|
+
|
|
92
|
+
const sound = resolveBase64(resolvedFile.data, resolvedContentType);
|
|
93
|
+
|
|
94
|
+
const body = { emoji_id: emojiId, emoji_name: emojiName, name, sound, volume };
|
|
95
|
+
|
|
96
|
+
const soundboardSound = await this.client.rest.post(Routes.guildSoundboardSounds(this.guild.id), {
|
|
97
|
+
body,
|
|
98
|
+
reason,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return this._add(soundboardSound);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Data for editing a soundboard sound.
|
|
106
|
+
* @typedef {Object} GuildSoundboardSoundEditOptions
|
|
107
|
+
* @property {string} [name] The name of the soundboard sound
|
|
108
|
+
* @property {?number} [volume] The volume of the soundboard sound, from 0 to 1
|
|
109
|
+
* @property {?Snowflake} [emojiId] The emoji id of the soundboard sound
|
|
110
|
+
* @property {?string} [emojiName] The emoji name of the soundboard sound
|
|
111
|
+
* @property {string} [reason] The reason for editing the soundboard sound
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Edits a soundboard sound.
|
|
116
|
+
* @param {SoundboardSoundResolvable} soundboardSound The soundboard sound to edit
|
|
117
|
+
* @param {GuildSoundboardSoundEditOptions} [options={}] The new data for the soundboard sound
|
|
118
|
+
* @returns {Promise<SoundboardSound>}
|
|
119
|
+
*/
|
|
120
|
+
async edit(soundboardSound, options = {}) {
|
|
121
|
+
const soundId = this.resolveId(soundboardSound);
|
|
122
|
+
|
|
123
|
+
if (!soundId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'soundboardSound', 'SoundboardSoundResolvable');
|
|
124
|
+
|
|
125
|
+
const { emojiId, emojiName, name, reason, volume } = options;
|
|
126
|
+
|
|
127
|
+
const body = { emoji_id: emojiId, emoji_name: emojiName, name, volume };
|
|
128
|
+
|
|
129
|
+
const data = await this.client.rest.patch(Routes.guildSoundboardSound(this.guild.id, soundId), {
|
|
130
|
+
body,
|
|
131
|
+
reason,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const existing = this.cache.get(soundId);
|
|
135
|
+
|
|
136
|
+
if (existing) {
|
|
137
|
+
const clone = existing._clone();
|
|
138
|
+
|
|
139
|
+
clone._patch(data);
|
|
140
|
+
return clone;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return this._add(data);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Deletes a soundboard sound.
|
|
148
|
+
* @param {SoundboardSoundResolvable} soundboardSound The soundboard sound to delete
|
|
149
|
+
* @param {string} [reason] Reason for deleting this soundboard sound
|
|
150
|
+
* @returns {Promise<void>}
|
|
151
|
+
*/
|
|
152
|
+
async delete(soundboardSound, reason) {
|
|
153
|
+
const soundId = this.resolveId(soundboardSound);
|
|
154
|
+
|
|
155
|
+
if (!soundId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'soundboardSound', 'SoundboardSoundResolvable');
|
|
156
|
+
|
|
157
|
+
await this.client.rest.delete(Routes.guildSoundboardSound(this.guild.id, soundId), { reason });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Obtains one or more soundboard sounds from Discord, or the soundboard sound cache if they're already available.
|
|
162
|
+
* @param {Snowflake} [id] The soundboard sound's id
|
|
163
|
+
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
|
164
|
+
* @returns {Promise<SoundboardSound|Collection<Snowflake, SoundboardSound>>}
|
|
165
|
+
* @example
|
|
166
|
+
* // Fetch all soundboard sounds from the guild
|
|
167
|
+
* guild.soundboardSounds.fetch()
|
|
168
|
+
* .then(sounds => console.log(`There are ${sounds.size} soundboard sounds.`))
|
|
169
|
+
* .catch(console.error);
|
|
170
|
+
* @example
|
|
171
|
+
* // Fetch a single soundboard sound
|
|
172
|
+
* guild.soundboardSounds.fetch('222078108977594368')
|
|
173
|
+
* .then(sound => console.log(`The soundboard sound name is: ${sound.name}`))
|
|
174
|
+
* .catch(console.error);
|
|
175
|
+
*/
|
|
176
|
+
async fetch(id, { cache = true, force = false } = {}) {
|
|
177
|
+
if (id) {
|
|
178
|
+
if (!force) {
|
|
179
|
+
const existing = this.cache.get(id);
|
|
180
|
+
if (existing) return existing;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const sound = await this.client.rest.get(Routes.guildSoundboardSound(this.guild.id, id));
|
|
184
|
+
return this._add(sound, cache);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const data = await this.client.rest.get(Routes.guildSoundboardSounds(this.guild.id));
|
|
188
|
+
return new Collection(data.map(sound => [sound.sound_id, this._add(sound, cache)]));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
exports.GuildSoundboardSoundManager = GuildSoundboardSoundManager;
|
package/src/structures/Guild.js
CHANGED
|
@@ -21,6 +21,7 @@ const { GuildEmojiManager } = require('../managers/GuildEmojiManager.js');
|
|
|
21
21
|
const { GuildInviteManager } = require('../managers/GuildInviteManager.js');
|
|
22
22
|
const { GuildMemberManager } = require('../managers/GuildMemberManager.js');
|
|
23
23
|
const { GuildScheduledEventManager } = require('../managers/GuildScheduledEventManager.js');
|
|
24
|
+
const { GuildSoundboardSoundManager } = require('../managers/GuildSoundboardSoundManager.js');
|
|
24
25
|
const { GuildStickerManager } = require('../managers/GuildStickerManager.js');
|
|
25
26
|
const { PresenceManager } = require('../managers/PresenceManager.js');
|
|
26
27
|
const { RoleManager } = require('../managers/RoleManager.js');
|
|
@@ -107,6 +108,12 @@ class Guild extends AnonymousGuild {
|
|
|
107
108
|
*/
|
|
108
109
|
this.autoModerationRules = new AutoModerationRuleManager(this);
|
|
109
110
|
|
|
111
|
+
/**
|
|
112
|
+
* A manager of the soundboard sounds of this guild.
|
|
113
|
+
* @type {GuildSoundboardSoundManager}
|
|
114
|
+
*/
|
|
115
|
+
this.soundboardSounds = new GuildSoundboardSoundManager(this);
|
|
116
|
+
|
|
110
117
|
if (!data) return;
|
|
111
118
|
if (data.unavailable) {
|
|
112
119
|
/**
|
|
@@ -34,7 +34,6 @@ const Targets = {
|
|
|
34
34
|
Unknown: 'Unknown',
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
// TODO: Add soundboard sounds when https://github.com/discordjs/discord.js/pull/10590 is merged
|
|
38
37
|
/**
|
|
39
38
|
* The target of a guild audit log entry. It can be one of:
|
|
40
39
|
* * A guild
|
|
@@ -52,10 +51,11 @@ const Targets = {
|
|
|
52
51
|
* * An application command
|
|
53
52
|
* * An auto moderation rule
|
|
54
53
|
* * A guild onboarding prompt
|
|
54
|
+
* * A soundboard sound
|
|
55
55
|
* * An object with an id key if target was deleted or fake entity
|
|
56
56
|
* * An object where the keys represent either the new value or the old value
|
|
57
57
|
* @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Integration|StageInstance|Sticker|
|
|
58
|
-
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule|GuildOnboardingPrompt)} AuditLogEntryTarget
|
|
58
|
+
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule|GuildOnboardingPrompt|SoundboardSound)} AuditLogEntryTarget
|
|
59
59
|
*/
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -369,9 +369,8 @@ class GuildAuditLogsEntry {
|
|
|
369
369
|
this.target = guild.roles.cache.get(data.target_id) ?? { id: data.target_id };
|
|
370
370
|
} else if (targetType === Targets.Emoji) {
|
|
371
371
|
this.target = guild.emojis.cache.get(data.target_id) ?? { id: data.target_id };
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
// this.target = guild.soundboardSounds.cache.get(data.target_id) ?? { id: data.target_id };
|
|
372
|
+
} else if (targetType === Targets.SoundboardSound) {
|
|
373
|
+
this.target = guild.soundboardSounds.cache.get(data.target_id) ?? { id: data.target_id };
|
|
375
374
|
} else if (data.target_id) {
|
|
376
375
|
this.target = { id: data.target_id };
|
|
377
376
|
}
|