Skip to content

Instantly share code, notes, and snippets.

@bsian03
Last active March 13, 2022 11:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bsian03/90bdb4a168233b2cfd9c33b3598b83ed to your computer and use it in GitHub Desktop.
Save bsian03/90bdb4a168233b2cfd9c33b3598b83ed to your computer and use it in GitHub Desktop.
A quick guide on how to use Eris' voice features

Using voice features with Eris

FAQ

Question Answer
I'm getting Error: Invalid converter command, why? Either you don't have FFmpeg/avconv binaries installed or it isn't in your environment variables (see below)
Can I use the ffmpeg from NPM? No, the ffmpeg module on NPM is used to interact with an installed FFmpeg binary, it is not FFmpeg itself

Requirements

  • node-gyp and its dependencies, but in summary:
    • Python 3.6/3.7/3.8/3.9 (or latest version from the Windows Store if applicable)
    • C/C++ compiler toolchain (GCC as an example)
  • FFmpeg (see below) or avconv

FFmpeg Installation (follow the relevant OS instructions)

Linux (most if not all distros can follow this)

  1. Update your apt package list:
    $ sudo apt update
  2. Install the FFmpeg package:
    $ sudo apt install ffmpeg
  3. Make sure FFmpeg is successfully installed (the latest version at time of writing is 4.1.6 on Debian 10, 4.2.4 on Ubuntu 20.04, 4.3.1 on Ubuntu 20.10 and 4.3.2 on Ubuntu 21.04):
    $ ffmpeg -version

Windows

  1. Download the Windows build from either gyan.dev (scroll down and click on the ffmpeg-git-full.7z link) or BtbN (find the win64-gpl zip file)*
  2. Extract the contents of the 7z/zip file to C:\Program Files\ffmpeg (should contain at minimum the bin folder)
  3. Open the System Properties window (Settings → System → About → Advanced System Settings or search for "View Advanced System Settings")
  4. Open the Environment Variables window
  5. Select the "Path" variable then click "Edit..."
  6. In the Edit Environment Variable window, click on "New", then type C:\Program Files\ffmpeg\bin
  7. Click "OK" in the Edit Environment Variable and Environment Variables windows
  8. Make sure FFmpeg is successfully installed (the current latest version at time of writing is 4.4):
    ffmpeg -version

* These links are not official FFmpeg websites and may not be affiliated with FFmpeg. They are simply trustworthy sources to download precompiled Windows binaries for FFmpeg, as they do not distribute precompiled binaries themselves. These links, however, are linked from FFmpeg's website

MacOS

  1. Update your homebrew package list:
    $ brew update
  2. Install the FFmpeg package:
    $ brew install ffmpeg
  3. Make sure FFmpeg is successfully installed (the current latest version at time of writing is 4.4):
    $ ffmpeg -version

Manual installation

Please follow the relevant compilation guide for your operating system

Playing audio (quick guide)

NOTE I must stress that the following code are basic instructions on how to use voice with Eris. Please do not copy this code blindly as your code will almost certainly differ to the example guide given here.

To play audio, you must first connect to a voice channel

const Eris = require("eris");
const bot = new Eris.Client("Bot TOKEN"); // Replace TOKEN with your bot account token

// After client ready and after invokation (must be inside an asynchronous function if not using promise callbacks)
const voiceConnection = await bot.joinVoiceChannel(channelID);

After connecting to the voice channel, you must wait for Discord to tell your bot that it has connected successfully

voiceConnection.on("ready", () => {
    console.log("Successfully connected to the voice channel");
});

Now your bot is ready to start streaming audio to the voice channel. We can either play a local audio file or something from YouTube (in this example we'll use ytdl-core) (make sure you do this in the ready event)

voiceConnection.on("ready", () => {
    console.log("Successfully connected to the voice channel");
    voiceConnection.play(pathToFile);
});
const ytdl = require("ytdl-core");
voiceConnection.on("ready", () => {
    console.log("Successfully connected to the voice channel");
    voiceConnection.play(ytdl(youtubeURL));
});

In some cases you might want to pass a ReadableStream directly into Eris, in this case, follow the same format as playing a local file, but set the parameter to the ReadableStream instead of a filepath string

Combining all of this (as well as adding some other checks and user friendly indications), you might get something along the lines of this:

const Eris = require("eris");
const bot = new Eris.Client("Bot TOKEN"); // Replace TOKEN with your bot account token

const playCommand = "!play";

bot.on("ready", () => { // When the bot is ready
    console.log("Ready!"); // Log "Ready!"
});

bot.on("error", (err) => {
    console.error(err); // or your preferred logger
});

bot.on("messageCreate", async (msg) => { // When a message is created
    if(msg.content.startsWith(playCommand)) { // If the message content starts with "!play "
        if(msg.content.length <= playCommand.length + 1) { // Check if a filename was specified
            bot.createMessage(msg.channel.id, "Please specify a filename.");
            return;
        }
        if(!msg.channel.guild) { // Check if the message was sent in a guild
            bot.createMessage(msg.channel.id, "This command can only be run in a server.");
            return;
        }
        if(!msg.member.voiceState.channelID) { // Check if the user is in a voice channel
            bot.createMessage(msg.channel.id, "You are not in a voice channel.");
            return;
        }
        const filename = msg.content.substring(playCommand.length + 1); // Get the filename
        try {
            const voiceConnection = await bot.joinVoiceChannel(msg.member.voiceState.channelID);
            voiceConnection.on("ready", () => {
                console.log("Successfully connected to the voice channel");
                if(voiceConnection.playing) { // Stop playing if the connection is playing something
                    voiceConnection.stopPlaying();
                }
                voiceConnection.play(filename); // Play the file and notify the user
                bot.createMessage(msg.channel.id, `Now playing **${filename}**`);
                voiceConnection.once("end", () => {
                    bot.createMessage(msg.channel.id, `Finished **${filename}**`); // Say when the file has finished playing
                });
            });
        } catch (error) {
            bot.createMessage(msg.channel.id, "Error joining voice channel: " + error.message); // Notify the user if there is an error
            console.log(error); // Log the error
        }
    }
});

bot.connect(); // Get the bot to connect to Discord

You can modify this to support ytdl-core and searching videos on YouTube.

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