discord.js-selfbot-v13
Version:
A unofficial discord.js fork for creating selfbots [Based on discord.js v13]
151 lines (135 loc) • 4.85 kB
JavaScript
const VoiceConnection = require('./VoiceConnection');
const { Error } = require('../../errors');
const { Events } = require('../../util/Constants');
/**
* Manages voice connections for the client
* Feat: Support both lib & djs/voice
*/
class ClientVoiceManager {
constructor(client) {
/**
* The client that instantiated this voice manager
* @type {Client}
* @readonly
* @name ClientVoiceManager#client
*/
Object.defineProperty(this, 'client', { value: client });
/**
* A current connection objects
* @type {?VoiceConnection}
*/
this.connection = null;
/**
* Maps guild ids to voice adapters created for use with @discordjs/voice.
* @type {Map<Snowflake, Object>}
*/
this.adapters = new Map();
client.on(Events.SHARD_DISCONNECT, (_, shardId) => {
for (const [guildId, adapter] of this.adapters.entries()) {
if (client.guilds.cache.get(guildId)?.shardId === shardId) {
// Because it has 1 shard => adapter.destroy();
}
adapter.destroy();
}
});
}
onVoiceServer(payload) {
const { guild_id, channel_id, token, endpoint } = payload;
this.client.emit(
'debug',
`[VOICE] voiceServer ${channel_id ? 'channel' : 'guild'}: ${
channel_id || guild_id
} token: ${token} endpoint: ${endpoint}`,
);
const connection = this.connection;
if (connection) connection.setTokenAndEndpoint(token, endpoint);
// Djs / voice
if (payload.guild_id) {
this.adapters.get(payload.guild_id)?.onVoiceServerUpdate(payload);
} else {
this.adapters.get(payload.channel_id)?.onVoiceServerUpdate(payload);
}
}
onVoiceStateUpdate(payload) {
const { guild_id, session_id, channel_id } = payload;
const connection = this.connection;
this.client.emit('debug', `[VOICE] connection? ${!!connection}, ${guild_id} ${session_id} ${channel_id}`);
if (!connection) return;
if (!channel_id) {
connection._disconnect();
this.connection = null;
return;
}
const channel = this.client.channels.cache.get(channel_id);
if (channel) {
connection.channel = channel;
connection.setSessionId(session_id);
} else {
this.client.emit('debug', `[VOICE] disconnecting from guild ${guild_id} as channel ${channel_id} is uncached`);
connection.disconnect();
}
// Djs Voice
if (payload.guild_id && payload.session_id && payload.user_id === this.client.user?.id) {
this.adapters.get(payload.guild_id)?.onVoiceStateUpdate(payload);
} else if (payload.channel_id && payload.session_id && payload.user_id === this.client.user?.id) {
this.adapters.get(payload.channel_id)?.onVoiceStateUpdate(payload);
}
}
/**
* @property {boolean} [selfMute=false]
* @property {boolean} [selfDeaf=false]
* @property {boolean} [selfVideo=false]
* @property {VideoCodec} [videoCodec='H264']
* @typedef {Object} JoinChannelConfig
*/
/**
* Sets up a request to join a voice channel.
* @param {VoiceChannel | StageChannel | DMChannel | GroupDMChannel | Snowflake} channel The voice channel to join
* @param {JoinChannelConfig} config Config to join voice channel
* @returns {Promise<VoiceConnection>}
*/
joinChannel(channel, config = {}) {
return new Promise((resolve, reject) => {
channel = this.client.channels.resolve(channel);
if (!['DM', 'GROUP_DM'].includes(channel?.type) && !channel.joinable) {
throw new Error('VOICE_JOIN_CHANNEL', channel.full);
}
let connection = this.connection;
if (connection) {
if (connection.channel.id !== channel.id) {
this.connection.updateChannel(channel);
}
resolve(connection);
return;
} else {
connection = new VoiceConnection(this, channel);
if (config?.videoCodec) connection.setVideoCodec(config.videoCodec);
connection.on('debug', msg =>
this.client.emit('debug', `[VOICE (${channel.guild?.id || channel.id}:${connection.status})]: ${msg}`),
);
connection.authenticate({
self_mute: Boolean(config.selfMute),
self_deaf: Boolean(config.selfDeaf),
self_video: Boolean(config.selfVideo),
});
this.connection = connection;
}
connection.once('failed', reason => {
this.connection = null;
reject(reason);
});
connection.on('error', reject);
connection.once('authenticated', () => {
connection.once('ready', () => {
resolve(connection);
connection.removeListener('error', reject);
});
connection.once('disconnect', () => {
this.connection = null;
});
});
});
}
}
module.exports = ClientVoiceManager;
;