import { NoSubscriberBehavior, StreamType, createAudioPlayer, createAudioResource, entersState, AudioPlayerStatus, VoiceConnectionStatus, joinVoiceChannel, } from '@discordjs/voice'; import { GatewayIntentBits } from 'discord-api-types/v10'; import { Client, Events } from 'discord.js'; import prism_media from 'prism-media'; const { FFmpeg } = prism_media; const device = "VoiceMeeter VAIO3 Output (VB-Audio VoiceMeeter VAIO3)", maxTransmissionGap = 500, type = "dshow"; const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play, maxMissedFrames: Math.round(maxTransmissionGap / 20), }, }); function attachRecorder() { player.play( createAudioResource( new FFmpeg({ args: [ '-analyzeduration', '0', '-loglevel', '0', '-f', type, '-i', type === 'dshow' ? `audio=${device}` : device, '-acodec', 'libopus', '-f', 'opus', '-ar', '48000', '-ac', '2', ], }), { inputType: StreamType.OggOpus, }, ), ); console.log('Attached recorder - ready to go!'); } player.on('stateChange', (oldState, newState) => { if (oldState.status === AudioPlayerStatus.Idle && newState.status === AudioPlayerStatus.Playing) { console.log('Playing audio output on audio player'); } else if (newState.status === AudioPlayerStatus.Idle) { console.log('Playback has stopped. Attempting to restart.'); attachRecorder(); } }); /** * * @param {any} channel * @returns {any} */ export async function connectToChannel(channel) { const connection = joinVoiceChannel({ channelId: channel.id, guildId: channel.guild.id, adapterCreator: channel.guild.voiceAdapterCreator, }); try { await entersState(connection, VoiceConnectionStatus.Ready, 30_000); return connection; } catch (error) { connection.destroy(); throw error; } } export async function getVoiceChannelFromID(client, channelID) { return client.channels.cache.get(channelID) } export async function initDiscordBotClient(token, readyCallback){ const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.MessageContent], }); client.on(Events.ClientReady, () => { console.log('discord.js client is ready!'); attachRecorder(); readyCallback(client); }); client.on(Events.MessageCreate, async (message) => { if (!message.guild) return; console.log(`New Message:`, message.content); if (message.content === '-join') { const channel = message.member?.voice.channel; if (channel) { try { const connection = await connectToChannel(channel); connection.subscribe(player); await message.reply('Playing now!'); } catch (error) { console.error(error); } } else { await message.reply('Join a voice channel then try again!'); } } }); client.login(token); }