UNPKG

@getsolara/solara.voice

Version:

Optional voice functionality for @getsolara/solara.js using @discordjs/voice

68 lines (65 loc) 4.02 kB
const { joinVoiceChannel, VoiceConnectionStatus, entersState } = require('@discordjs/voice'); module.exports = { name: "$voiceJoin", description: "Makes the bot join the user's current voice channel or a specified channel. Args: [channelID]", takesBrackets: true, execute: async (context, args) => { if (context.client.voiceInitialized === false) { return "[Error: $voiceJoin requires voice features to be enabled. Ensure @getsolara/solara.voice is installed and configured correctly.]"; } if (!context.guild) return "[Error: $voiceJoin can only be used in a server.]"; const targetChannelId = args[0]?.trim() || context.member?.voice?.channelId; if (!targetChannelId) return "[Error: You are not in a voice channel, and no channel ID was provided to $voiceJoin.]"; let voiceChannel; try { voiceChannel = await context.client.channels.fetch(targetChannelId); } catch { return `[Error: Could not find channel with ID ${targetChannelId} for $voiceJoin.]`; } if (!voiceChannel || !voiceChannel.isVoiceBased()) return `[Error: Channel ${targetChannelId} is not a voice channel for $voiceJoin.]`; if (!voiceChannel.joinable) return `[Error: Bot does not have permission to join voice channel: ${voiceChannel.name}]`; if (!voiceChannel.speakable && context.client.solaraOptions?.verboseStartupLogging) { console.warn(`Solara.voice ($voiceJoin): Bot might lack SPEAK permissions in channel ${voiceChannel.name}.`); } try { const existingConnection = context.client.solaraVoiceConnections?.get(context.guild.id); if (existingConnection) { if (existingConnection.joinConfig.channelId === voiceChannel.id && existingConnection.state.status === VoiceConnectionStatus.Ready) { return `Already connected to: ${voiceChannel.name}`; } existingConnection.destroy(); } const connection = joinVoiceChannel({ channelId: voiceChannel.id, guildId: context.guild.id, adapterCreator: context.guild.voiceAdapterCreator, selfDeaf: true, }); connection.on(VoiceConnectionStatus.Disconnected, async () => { try { await Promise.race([ entersState(connection, VoiceConnectionStatus.Signalling, 5_000), entersState(connection, VoiceConnectionStatus.Connecting, 5_000), ]); } catch (error) { if (connection.state.status !== VoiceConnectionStatus.Destroyed) connection.destroy(); } }); connection.on(VoiceConnectionStatus.Destroyed, () => { context.client.solaraVoiceConnections?.delete(context.guild.id); const player = context.client.solaraAudioPlayers?.get(context.guild.id); if (player) { player.stop(true); context.client.solaraAudioPlayers.delete(context.guild.id); } context.client.solaraVoiceQueues?.delete(context.guild.id); }); await entersState(connection, VoiceConnectionStatus.Ready, 20_000); context.client.solaraVoiceConnections?.set(context.guild.id, connection); return `Joined voice channel: ${voiceChannel.name}`; } catch (error) { console.error(`Solara.voice Error ($voiceJoin) for guild ${context.guild.id}:`, error); const conn = context.client.solaraVoiceConnections?.get(context.guild.id); if (conn && conn.state.status !== VoiceConnectionStatus.Destroyed) conn.destroy(); context.client.solaraVoiceConnections?.delete(context.guild.id); return `[Error joining voice channel: ${error.message}]`; } } };