Skip to content

Instantly share code, notes, and snippets.

@CTK-WARRIOR
Last active June 13, 2024 10:07
Show Gist options
  • Save CTK-WARRIOR/dcf9bdeee01ddf2a6f6cf0004ebd20ff to your computer and use it in GitHub Desktop.
Save CTK-WARRIOR/dcf9bdeee01ddf2a6f6cf0004ebd20ff to your computer and use it in GitHub Desktop.
Record command using discord.js and discordjs/voice with node 17, watch video: https://www.youtube.com/watch?v=h7CC-8kTsGI
/* Required Modules */
const { entersState, joinVoiceChannel, VoiceConnectionStatus, EndBehaviorType } = require('@discordjs/voice');
const { createWriteStream } = require('node:fs');
const prism = require('prism-media');
const { pipeline } = require('node:stream');
const { Client, Intents, MessageAttachment, Collection } = require('discord.js');
const ffmpeg = require('ffmpeg');
const sleep = require('util').promisify(setTimeout);
const fs = require('fs');
/* Initialize Discord Client */
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_VOICE_STATES
]
})
/* Collection to store voice state */
client.voiceManager = new Collection()
/* Ready event */
client.on("ready", () => {
console.log("Connected as", client.user.tag, "to discord!");
})
/* When message is sent*/
client.on('messageCreate', async (message) => {
/* If content starts with `!record` */
if (message.content.startsWith('!record')) {
/* If member do not have admin perms */
if (!message.member.permissions.has('ADMINISTRATOR')) return message.channel.send('You do not have permission to use this command.');
/* Get the voice channel the user is in */
const voiceChannel = message.member.voice.channel
/* Check if the bot is in voice channel */
let connection = client.voiceManager.get(message.channel.guild.id)
/* If the bot is not in voice channel */
if (!connection) {
/* if user is not in any voice channel then return the error message */
if(!voiceChannel) return message.channel.send("You must be in a voice channel to use this command!")
/* Join voice channel*/
connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: voiceChannel.guild.id,
selfDeaf: false,
selfMute: true,
adapterCreator: voiceChannel.guild.voiceAdapterCreator,
});
/* Add voice state to collection */
client.voiceManager.set(message.channel.guild.id, connection);
await entersState(connection, VoiceConnectionStatus.Ready, 20e3);
const receiver = connection.receiver;
/* When user speaks in vc*/
receiver.speaking.on('start', (userId) => {
if(userId !== message.author.id) return;
/* create live stream to save audio */
createListeningStream(receiver, userId, client.users.cache.get(userId));
});
/* Return success message */
return message.channel.send(`πŸŽ™οΈ I am now recording ${voiceChannel.name}`);
/* If the bot is in voice channel */
} else if (connection) {
/* Send waiting message */
const msg = await message.channel.send("Please wait while I am preparing your recording...")
/* wait for 5 seconds */
await sleep(5000)
/* disconnect the bot from voice channel */
connection.destroy();
/* Remove voice state from collection */
client.voiceManager.delete(message.channel.guild.id)
const filename = `./recordings/${message.author.id}`;
/* Create ffmpeg command to convert pcm to mp3 */
const process = new ffmpeg(`${filename}.pcm`);
process.then(function (audio) {
audio.fnExtractSoundToMP3(`${filename}.mp3`, async function (error, file) {
//edit message with recording as attachment
await msg.edit({
content: `πŸ”‰ Here is your recording!`,
files: [new MessageAttachment(`./recordings/${message.author.id}.mp3`, 'recording.mp3')]
});
//delete both files
fs.unlinkSync(`${filename}.pcm`)
fs.unlinkSync(`${filename}.mp3`)
});
}, function (err) {
/* handle error by sending error message to discord */
return msg.edit(`❌ An error occurred while processing your recording: ${err.message}`);
});
}
}
})
client.login("BOT TOKEN")
//------------------------- F U N C T I O N S ----------------------//
/* Function to write audio to file (from discord.js example) */
function createListeningStream(receiver, userId, 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/${user.id}.pcm`;
const out = createWriteStream(filename, { flags: 'a' });
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}`);
}
});
}
@APRILDAY23
Copy link

APRILDAY23 commented Apr 14, 2024

ream function and set the crc parameter as false for oggStream

node:internal/process/promises:279 triggerUncaughtException(err, true /* fromPromise */); ^

[Error: ENOENT: no such file or directory, stat 'C:\Users\User\Desktop\SPBYSHI\recordings\682296526835548175.mp3'] { errno: -4058, code: 'ENOENT', syscall: 'stat', path: 'C:\Users\User\Desktop\SPBYSHI\recordings\682296526835548175.mp3' }

did you manage to solve this in discord js v14? Getting the same error. I have ffmpeg installed on my pc and package as well

const { entersState, joinVoiceChannel, VoiceConnectionStatus, EndBehaviorType } = require('@discordjs/voice');
const { createWriteStream } = require('node:fs');
const prism = require('prism-media');
const { pipeline } = require('node:stream');
const ffmpeg = require('ffmpeg');
const sleep = require('util').promisify(setTimeout);

/* Collection to store voice state */
client.voiceManager = new Collection()


/* When message is sent*/
client.on('messageCreate', async (message) => {
    /* If content starts with `!record` */
    if (message.content.startsWith('!record')) {
        /* If member do not have admin perms */
        if (!message.member.permissions.has('ADMINISTRATOR')) return message.channel.send('You do not have permission to use this command.'); 
        /* Get the voice channel the user is in */
        const voiceChannel = message.member.voice.channel
        /* Check if the bot is in voice channel */
        let connection = client.voiceManager.get(message.channel.guild.id)

        /* If the bot is not in voice channel */
        if (!connection) {
            /* if user is not in any voice channel then return the error message */
            if(!voiceChannel) return message.channel.send("You must be in a voice channel to use this command!")

            /* Join voice channel*/
            connection = joinVoiceChannel({
                channelId: voiceChannel.id,
                guildId: voiceChannel.guild.id,
                selfDeaf: false,
                selfMute: true,
                adapterCreator: voiceChannel.guild.voiceAdapterCreator,
            });

            /* Add voice state to collection */
            client.voiceManager.set(message.channel.guild.id, connection);
            await entersState(connection, VoiceConnectionStatus.Ready, 20e3);
            const receiver = connection.receiver;

            /* When user speaks in vc*/
            receiver.speaking.on('start', (userId) => {
                if(userId !== message.author.id) return;
                /* create live stream to save audio */
                createListeningStream(receiver, userId, client.users.cache.get(userId));
            });

            /* Return success message */
            return message.channel.send(`πŸŽ™οΈ I am now recording ${voiceChannel.name}`);
        
            /* If the bot is in voice channel */
        } else if (connection) {
            /* Send waiting message */
            const msg = await message.channel.send("Please wait while I am preparing your recording...")
            /* wait for 5 seconds */
            await sleep(5000)

            /* disconnect the bot from voice channel */
            connection.destroy();

            /* Remove voice state from collection */
            client.voiceManager.delete(message.channel.guild.id)
            
            const filename = `./Recordings/${message.author.id}`;

            /* Create ffmpeg command to convert pcm to mp3 */
            const process = new ffmpeg(`${filename}.pcm`);
            process.then(function (audio) {
                audio.fnExtractSoundToMP3(`${filename}.mp3`, async function (error, file) {
                    //edit message with recording as attachment
                    await msg.edit({
                        content: `πŸ”‰ Here is your recording!`,
                        files: [
                            {
                                attachment: `${filename}.mp3`,
                                name: "recording.mp3",
                            },
                        ],
                    });

                    //delete both files
                    fs.unlinkSync(`${filename}.pcm`)
                    fs.unlinkSync(`${filename}.mp3`)
                });
            }, function (err) {
                /* handle error by sending error message to discord */
                return msg.edit(`❌ An error occurred while processing your recording: ${err.message}`);
            });

        }
    }
})

//------------------------- F U N C T I O N S ----------------------//

/* Function to write audio to file (from discord.js example) */
function createListeningStream(receiver, userId, user) {
  const opusStream = receiver.subscribe(userId, {
      end: {
          behavior: EndBehaviorType.AfterSilence,
          duration: 100,
      },
  });

  const filename = `./Recordings/${user.id}.pcm`;
  const out = createWriteStream(filename, { flags: 'a' });
  console.log(`πŸ‘‚ Started recording ${filename}`);

  const opusEncoder = new prism.opus.Encoder({
      rate: 48000,
      channels: 2,
      frameSize: 960,
      quality: 10,
      crc: false,
  });

  pipeline(opusStream, opusEncoder, out, (err) => {
      if (err) {
          console.warn(`❌ Error recording file ${filename} - ${err.message}`);
      } else {
          console.log(`βœ… Recorded ${filename}`);
      }
  });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment