Search code examples
javascripttypescriptdiscord.jsytdl

Typescript DiscordJS bot audio stops working after a few seconds of playing


I am currently facing an issue with playing audio through a bot I made for discord. The bot downloads a song from youtube using ytdl-core and then plays it, but the song stops after a few seconds of playing.

Here is my "play.ts" file, which includes the play command: (apologies for the messy code, I am just trying to put something together here.)

import { CommandInteraction, SlashCommandBuilder } from "discord.js";
import { getVoiceConnection, createAudioPlayer, createAudioResource, NoSubscriberBehavior } from '@discordjs/voice';
import { join } from "path";
import ytdl from 'ytdl-core';
import fs from 'fs';

export const data = new SlashCommandBuilder()
    .addStringOption(option =>
        option.setName("link")
            .setDescription("Link to the audio source to be played.")
            .setRequired(true)
    )
    .setName("play")
    .setDescription("Plays audio from given URL.");

export async function execute(interaction: CommandInteraction) {
    if (!interaction.guildId) {
        return interaction.reply("Something went really, really wrong.");
    }

    const url = interaction.options.getString("link");
    const connection = getVoiceConnection(interaction.guildId);

    if (!connection) {
        return interaction.reply("Bot is not currently in a voice channel. Join one before using this command.");
    }

    const audioplayer = createAudioPlayer({
        behaviors: {
            noSubscriber: NoSubscriberBehavior.Pause,
        },
    });

    const download = ytdl(url, { filter: 'audioonly' });
    const writestream = fs.createWriteStream('audio.mp4');
    const pathtoresource = join('audio.mp4');
    // console.log(pathtoresource);

    download.pipe(writestream);

    const resource = createAudioResource(pathtoresource, {
        inlineVolume: true,
        metadata: {
            title: "SONG",
        },
    });

    audioplayer.play(resource);
    connection.subscribe(audioplayer);

    return interaction.reply(`Playing from: ${url}`);
}

It should play the audio after downloading the song, but it sometimes plays a few seconds of the song, other times nothing at all. (maybe because the download isn't done in time to play, but I don't know how to make it wait for the ytdl download.)

Any help is much appreciated! (once again, apologies for the messy code, I am still learning)

EDIT: These are the intents:

const client = new Client({
    intents: ["Guilds", "GuildMessages", "DirectMessages", "GuildVoiceStates" ],
});

Solution

  • What you're experiencing isn't an issue with Discord intents. ytdl-core wasn't designed with the intent of keeping HTTP connections open for long periods of time. This happens when streaming media to something that consumes the data at a slower rate than the rate it is being fed the data.

    Another npm package known as play-dl solves this issue (and adds support for other streaming services which is a real cherry on top). Check out it's example Discord bot code here to see how it's used.

    In my old Discord bot projects, I used play-dl after experiencing the same issue with ytdl-core, and things went smoothly. If you need further help, ask me in a comment on this post.