mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-13 01:53:30 +01:00
chore: monorepo setup (#7175)
This commit is contained in:
46
packages/voice/examples/recorder/src/bot.ts
Normal file
46
packages/voice/examples/recorder/src/bot.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import Discord, { Interaction } from 'discord.js';
|
||||
import { getVoiceConnection } from '@discordjs/voice';
|
||||
import { deploy } from './deploy';
|
||||
import { interactionHandlers } from './interactions';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
||||
const { token } = require('../auth.json');
|
||||
|
||||
const client = new Discord.Client({ intents: ['GUILD_VOICE_STATES', 'GUILD_MESSAGES', 'GUILDS'] });
|
||||
|
||||
client.on('ready', () => console.log('Ready!'));
|
||||
|
||||
client.on('messageCreate', async (message) => {
|
||||
if (!message.guild) return;
|
||||
if (!client.application?.owner) await client.application?.fetch();
|
||||
|
||||
if (message.content.toLowerCase() === '!deploy' && message.author.id === client.application?.owner?.id) {
|
||||
await deploy(message.guild);
|
||||
await message.reply('Deployed!');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The IDs of the users that can be recorded by the bot.
|
||||
*/
|
||||
const recordable = new Set<string>();
|
||||
|
||||
client.on('interactionCreate', async (interaction: Interaction) => {
|
||||
if (!interaction.isCommand() || !interaction.guildId) return;
|
||||
|
||||
const handler = interactionHandlers.get(interaction.commandName);
|
||||
|
||||
try {
|
||||
if (handler) {
|
||||
await handler(interaction, recordable, client, getVoiceConnection(interaction.guildId));
|
||||
} else {
|
||||
await interaction.reply('Unknown command');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('error', console.warn);
|
||||
|
||||
void client.login(token);
|
||||
@@ -0,0 +1,42 @@
|
||||
import { EndBehaviorType, VoiceReceiver } from '@discordjs/voice';
|
||||
import { User } from 'discord.js';
|
||||
import { createWriteStream } from 'node:fs';
|
||||
import prism from 'prism-media';
|
||||
import { pipeline } from 'node:stream';
|
||||
|
||||
function getDisplayName(userId: string, user?: User) {
|
||||
return user ? `${user.username}_${user.discriminator}` : userId;
|
||||
}
|
||||
|
||||
export function createListeningStream(receiver: VoiceReceiver, userId: string, user?: User) {
|
||||
const opusStream = receiver.subscribe(userId, {
|
||||
end: {
|
||||
behavior: EndBehaviorType.AfterSilence,
|
||||
duration: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const oggStream = new prism.opus.OggLogicalBitstream({
|
||||
opusHead: new prism.opus.OpusHead({
|
||||
channelCount: 2,
|
||||
sampleRate: 48000,
|
||||
}),
|
||||
pageSizeControl: {
|
||||
maxPackets: 10,
|
||||
},
|
||||
});
|
||||
|
||||
const filename = `./recordings/${Date.now()}-${getDisplayName(userId, user)}.ogg`;
|
||||
|
||||
const out = createWriteStream(filename);
|
||||
|
||||
console.log(`👂 Started recording ${filename}`);
|
||||
|
||||
pipeline(opusStream, oggStream, out, (err) => {
|
||||
if (err) {
|
||||
console.warn(`❌ Error recording file ${filename} - ${err.message}`);
|
||||
} else {
|
||||
console.log(`✅ Recorded ${filename}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
26
packages/voice/examples/recorder/src/deploy.ts
Normal file
26
packages/voice/examples/recorder/src/deploy.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Guild } from 'discord.js';
|
||||
|
||||
export const deploy = async (guild: Guild) => {
|
||||
await guild.commands.set([
|
||||
{
|
||||
name: 'join',
|
||||
description: 'Joins the voice channel that you are in',
|
||||
},
|
||||
{
|
||||
name: 'record',
|
||||
description: 'Enables recording for a user',
|
||||
options: [
|
||||
{
|
||||
name: 'speaker',
|
||||
type: 'USER' as const,
|
||||
description: 'The user to record',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'leave',
|
||||
description: 'Leave the voice channel',
|
||||
},
|
||||
]);
|
||||
};
|
||||
92
packages/voice/examples/recorder/src/interactions.ts
Normal file
92
packages/voice/examples/recorder/src/interactions.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { entersState, joinVoiceChannel, VoiceConnection, VoiceConnectionStatus } from '@discordjs/voice';
|
||||
import { Client, CommandInteraction, GuildMember, Snowflake } from 'discord.js';
|
||||
import { createListeningStream } from './createListeningStream';
|
||||
|
||||
async function join(
|
||||
interaction: CommandInteraction,
|
||||
recordable: Set<Snowflake>,
|
||||
client: Client,
|
||||
connection?: VoiceConnection,
|
||||
) {
|
||||
await interaction.deferReply();
|
||||
if (!connection) {
|
||||
if (interaction.member instanceof GuildMember && interaction.member.voice.channel) {
|
||||
const channel = interaction.member.voice.channel;
|
||||
connection = joinVoiceChannel({
|
||||
channelId: channel.id,
|
||||
guildId: channel.guild.id,
|
||||
selfDeaf: false,
|
||||
selfMute: true,
|
||||
adapterCreator: channel.guild.voiceAdapterCreator,
|
||||
});
|
||||
} else {
|
||||
await interaction.followUp('Join a voice channel and then try that again!');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await entersState(connection, VoiceConnectionStatus.Ready, 20e3);
|
||||
const receiver = connection.receiver;
|
||||
|
||||
receiver.speaking.on('start', (userId) => {
|
||||
if (recordable.has(userId)) {
|
||||
createListeningStream(receiver, userId, client.users.cache.get(userId));
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
await interaction.followUp('Failed to join voice channel within 20 seconds, please try again later!');
|
||||
}
|
||||
|
||||
await interaction.followUp('Ready!');
|
||||
}
|
||||
|
||||
async function record(
|
||||
interaction: CommandInteraction,
|
||||
recordable: Set<Snowflake>,
|
||||
client: Client,
|
||||
connection?: VoiceConnection,
|
||||
) {
|
||||
if (connection) {
|
||||
const userId = interaction.options.get('speaker')!.value! as Snowflake;
|
||||
recordable.add(userId);
|
||||
|
||||
const receiver = connection.receiver;
|
||||
if (connection.receiver.speaking.users.has(userId)) {
|
||||
createListeningStream(receiver, userId, client.users.cache.get(userId));
|
||||
}
|
||||
|
||||
await interaction.reply({ ephemeral: true, content: 'Listening!' });
|
||||
} else {
|
||||
await interaction.reply({ ephemeral: true, content: 'Join a voice channel and then try that again!' });
|
||||
}
|
||||
}
|
||||
|
||||
async function leave(
|
||||
interaction: CommandInteraction,
|
||||
recordable: Set<Snowflake>,
|
||||
client: Client,
|
||||
connection?: VoiceConnection,
|
||||
) {
|
||||
if (connection) {
|
||||
connection.destroy();
|
||||
recordable.clear();
|
||||
await interaction.reply({ ephemeral: true, content: 'Left the channel!' });
|
||||
} else {
|
||||
await interaction.reply({ ephemeral: true, content: 'Not playing in this server!' });
|
||||
}
|
||||
}
|
||||
|
||||
export const interactionHandlers = new Map<
|
||||
string,
|
||||
(
|
||||
interaction: CommandInteraction,
|
||||
recordable: Set<Snowflake>,
|
||||
client: Client,
|
||||
connection?: VoiceConnection,
|
||||
) => Promise<void>
|
||||
>();
|
||||
interactionHandlers.set('join', join);
|
||||
interactionHandlers.set('record', record);
|
||||
interactionHandlers.set('leave', leave);
|
||||
Reference in New Issue
Block a user