Skip to content

Commit

Permalink
feat: add soundboard
Browse files Browse the repository at this point in the history
  • Loading branch information
sdanialraza committed Nov 20, 2024
1 parent 98153ba commit 57c2a7c
Show file tree
Hide file tree
Showing 16 changed files with 340 additions and 1 deletion.
9 changes: 9 additions & 0 deletions packages/discord.js/src/client/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const ActionsManager = require('./actions/ActionsManager');
const ClientVoiceManager = require('./voice/ClientVoiceManager');
const PacketHandlers = require('./websocket/handlers');
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
// TODO: Uncomment after finishing the manager
// const { BaseSoundboardSoundManager } = require('../managers/BaseSoundboardSoundManager');
const BaseGuildEmojiManager = require('../managers/BaseGuildEmojiManager');
const ChannelManager = require('../managers/ChannelManager');
const GuildManager = require('../managers/GuildManager');
Expand Down Expand Up @@ -176,6 +178,13 @@ class Client extends BaseClient {
*/
this.voice = new ClientVoiceManager(this);

// TODO: Uncomment after finishing the manager
// /**
// * The soundboard sound manager of the client
// * @type {BaseSoundboardSoundManager}
// */
// this.soundboardSounds = new BaseSoundboardSoundManager(this);

/**
* User that the client is logged in as
* @type {?ClientUser}
Expand Down
3 changes: 3 additions & 0 deletions packages/discord.js/src/client/actions/ActionsManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class ActionsManager {
this.register(require('./GuildScheduledEventUpdate'));
this.register(require('./GuildScheduledEventUserAdd'));
this.register(require('./GuildScheduledEventUserRemove'));
this.register(require('./GuildSoundboardSoundCreate'));
this.register(require('./GuildSoundboardSoundDelete'));
this.register(require('./GuildSoundboardSoundUpdate'));
this.register(require('./GuildStickerCreate'));
this.register(require('./GuildStickerDelete'));
this.register(require('./GuildStickerUpdate'));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const Action = require('./Action');
const Events = require('../../util/Events');

class GuildSoundboardSoundCreateAction extends Action {
handle(data) {
const guild = this.client.guilds.cache.get(data.guild_id);

let soundboardSound;

if (guild) {
const already = guild.soundboardSounds.cache.has(data.sound_id);

soundboardSound = guild.soundboardSounds._add(data);

/**
* Emitted whenever a soundboard sound is created in a guild.
* @event Client#guildSoundboardSoundCreate
* @param {SoundboardSound} soundboardSound The soundboard sound that was created
*/
if (!already) this.client.emit(Events.GuildSoundboardSoundCreate, soundboardSound);
}

return { soundboardSound };
}
}

module.exports = GuildSoundboardSoundCreateAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const Action = require('./Action');
const Events = require('../../util/Events');

class GuildSoundboardSoundDeleteAction extends Action {
handle(data) {
const guild = this.client.guilds.cache.get(data.guild_id);

let soundboardSound;

if (guild) {
soundboardSound = guild.soundboardSounds.cache._add(data, false);

guild.soundboardSounds.cache.delete(soundboardSound.id);

/**
* Emitted whenever a soundboard sound is deleted in a guild.
* @event Client#guildSoundboardSoundDelete
* @param {SoundboardSound} soundboardSound The soundboard sound that was deleted
*/
this.client.emit(Events.GuildSoundboardSoundDelete, soundboardSound);
}

return { soundboardSound };
}
}

module.exports = GuildSoundboardSoundDeleteAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

const Action = require('./Action');
const Events = require('../../util/Events');

class GuildSoundboardSoundUpdateAction extends Action {
handle(data) {
const guild = this.client.guilds.cache.get(data.guild_id);

if (guild) {
let oldSoundboardSound = null;

const newSoundboardSound = guild.soundboardSounds.cache.get(data.sound_id);

if (newSoundboardSound) {
oldSoundboardSound = newSoundboardSound._update(data);

/**
* Emitted whenever a soundboard sound is updated in a guild.
* @event Client#guildSoundboardSoundUpdate
* @param {?SoundboardSound} oldSoundboardSound The soundboard sound before the update
* @param {SoundboardSound} newSoundboardSound The soundboard sound after the update
*/
this.client.emit(Events.GuildSoundboardSoundUpdate, oldSoundboardSound, newSoundboardSound);
}

return { oldSoundboardSound, newSoundboardSound };
}

return { oldSoundboardSound: null, newSoundboardSound: null };
}
}

module.exports = GuildSoundboardSoundUpdateAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = (client, { d: data }) => {
client.actions.GuildSoundboardSoundCreate.handle(data);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = (client, { d: data }) => {
client.actions.GuildSoundboardSoundDelete.handle(data);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = (client, { d: data }) => {
client.actions.GuildSoundboardSoundUpdate.handle(data);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

const { Collection } = require('@discordjs/collection');
const Events = require('../../../util/Events');

module.exports = (client, { d: data }) => {
const guild = client.guilds.cache.get(data.guild_id);

if (!guild) return;

const soundboardSounds = new Collection();

for (const soundboardSound of data.soundboard_sounds) {
soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));
}

/**
* Emitted whenever soundboard sounds are received (all soundboard sounds come from the same guild).
* @event Client#soundboardSounds
* @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The sounds received
* @param {Guild} guild The guild related to the soundboard sounds
*/
client.emit(Events.SoundboardSounds, soundboardSounds, guild);
};
6 changes: 6 additions & 0 deletions packages/discord.js/src/client/websocket/handlers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ const handlers = Object.fromEntries([
['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE')],
['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD')],
['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE')],
['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE')],
['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE')],
['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE')],
// TODO: Uncomment this line after finishing the GUILD_SOUNDBOARD_SOUNDS_UPDATE handler
// ['GUILD_SOUNDBOARD_SOUNDS_UPDATE', require('./GUILD_SOUNDBOARD_SOUNDS_UPDATE')],
['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')],
['GUILD_UPDATE', require('./GUILD_UPDATE')],
['INTERACTION_CREATE', require('./INTERACTION_CREATE')],
Expand All @@ -49,6 +54,7 @@ const handlers = Object.fromEntries([
['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')],
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
['READY', require('./READY')],
['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS')],
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
Expand Down
5 changes: 5 additions & 0 deletions packages/discord.js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ exports.ApplicationEmojiManager = require('./managers/ApplicationEmojiManager');
exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager');
exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager');
exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager');
// TODO: Uncomment after finishing the manager
// exports.BaseSoundboardSoundManager = require('./managers/BaseSoundboardSoundManager').BaseSoundboardSoundManager;
exports.CachedManager = require('./managers/CachedManager');
exports.ChannelManager = require('./managers/ChannelManager');
exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager');
Expand All @@ -73,6 +75,8 @@ exports.GuildManager = require('./managers/GuildManager');
exports.GuildMemberManager = require('./managers/GuildMemberManager');
exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager');
exports.GuildMessageManager = require('./managers/GuildMessageManager');
// Uncomment after finishing the manager
// exports.GuildSoundboardSoundManager = require('./managers/GuildSoundboardSoundManager').GuildSoundboardSoundManager;
exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager');
exports.GuildStickerManager = require('./managers/GuildStickerManager');
exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager');
Expand Down Expand Up @@ -190,6 +194,7 @@ exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteract
exports.StringSelectMenuInteraction = require('./structures/StringSelectMenuInteraction');
exports.UserSelectMenuInteraction = require('./structures/UserSelectMenuInteraction');
exports.SKU = require('./structures/SKU').SKU;
exports.SoundboardSound = require('./structures/SoundboardSound').SoundboardSound;
exports.StringSelectMenuOptionBuilder = require('./structures/StringSelectMenuOptionBuilder');
exports.StageChannel = require('./structures/StageChannel');
exports.StageInstance = require('./structures/StageInstance').StageInstance;
Expand Down
9 changes: 9 additions & 0 deletions packages/discord.js/src/structures/Guild.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const VoiceStateManager = require('../managers/VoiceStateManager');
const { resolveImage } = require('../util/DataResolver');
const SystemChannelFlagsBitField = require('../util/SystemChannelFlagsBitField');
const { discordSort, getSortableGroupTypes, resolvePartialEmoji } = require('../util/Util');
// TODO: Uncomment this after finishing the manager
// const { GuildSoundboardSoundManager } = require('../managers/GuildSoundboardSoundManager');

/**
* Represents a guild (or a server) on Discord.
Expand Down Expand Up @@ -106,6 +108,13 @@ class Guild extends AnonymousGuild {
*/
this.autoModerationRules = new AutoModerationRuleManager(this);

// TODO: Remove this after finishing the manager
// /**
// * A manager of the soundboard sounds of this guild.
// * @type {GuildSoundboardSoundManager}
// */
// this.soundboardSounds = new GuildSoundboardSoundManager(this);

if (!data) return;
if (data.unavailable) {
/**
Expand Down
121 changes: 121 additions & 0 deletions packages/discord.js/src/structures/SoundboardSound.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use strict';

const Base = require('./Base');

/**
* Represents a soundboard sound.
* @extends {Base}
*/
class SoundboardSound extends Base {
constructor(client, data) {
super(client);

/**
* The id of the soundboard sound
* @type {Snowflake|number}
*/
this.soundId = data.sound_id;

this._patch(data);
}

_patch(data) {
/**
* Whether this soundboard sound is available
* @type {boolean}
*/
this.available = data.available;

/**
* The name of the soundboard sound
* @type {string}
*/
this.name = data.name;

/**
* The volume of the soundboard sound
* @type {number}
*/
this.volume = data.volume;

if ('emoji_id' in data) {
/**
* The emoji id of the soundboard sound
* @type {?Snowflake}
*/
this.emojiId = data.emojiId;
} else {
this.emojiId ??= null;
}

if ('emoji_name' in data) {
/**
* The emoji name of the soundboard sound
* @type {?string}
*/
this.emojiName = data.emojiName;
} else {
this.emojiName ??= null;
}

if ('guild_id' in data) {
/**
* The guild id of the soundboard sound
* @type {?Snowflake}
*/
this.guildId = data.guildId;
} else {
this.guildId ??= null;
}

if ('user' in data) {
/**
* The user who created this soundboard sound
* @type {?User}
*/
this.user = this.client.users._add(data.user);
} else {
this.user ??= null;
}
}

/**
* The guild this soundboard sound is part of
* @type {?Guild}
* @readonly
*/
get guild() {
return this.client.guilds.resolve(this.guildId);
}

/**
* Whether this soundboard sound is the same as another one.
* @param {SoundboardSound|APISoundboardSound} other The soundboard sound to compare it to
* @returns {boolean}
*/
equals(other) {
if (other instanceof SoundboardSound) {
return (
this.id === other.id &&
this.name === other.name &&
this.volume === other.volume &&
this.emojiId === other.emojiId &&
this.emojiName === other.emojiName &&
this.guildId === other.guildId &&
this.user?.id === other.user?.id
);
}

return (
this.id === other.sound_id &&
this.name === other.name &&
this.volume === other.volume &&
this.emojiId === other.emoji_id &&
this.emojiName === other.emoji_name &&
this.guildId === other.guild_id &&
this.user?.id === other.user?.id
);
}
}

exports.SoundboardSound = SoundboardSound;
17 changes: 16 additions & 1 deletion packages/discord.js/src/structures/VoiceChannel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const { PermissionFlagsBits } = require('discord-api-types/v10');
const { PermissionFlagsBits, Routes } = require('discord-api-types/v10');
const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');

/**
Expand Down Expand Up @@ -35,6 +35,21 @@ class VoiceChannel extends BaseGuildVoiceChannel {
permissions.has(PermissionFlagsBits.Speak, false)
);
}

/**
* Send a soundboard sound to a voice channel the user is connected to.
* Fires a Voice Channel Effect Send Gateway event.
* @param {SoundboardSound} sound the sound to send
* @returns {void}
*/
async sendSoundboardSound(sound) {
await this.client.rest.post(Routes.sendSoundboardSound(this.id), {
body: {
sound_id: sound.id,
source_guild_id: sound.guildId ?? undefined,
},
});
}
}

/**
Expand Down
Loading

0 comments on commit 57c2a7c

Please sign in to comment.