Getting started
3. Play a track
Register a /play command and start the bot.
You are reading the v8 docsDev
Create src/commands.ts with a /play command, and src/index.ts to register and dispatch commands.
The /play command
import {
ApplicationCommandOptionType,
MessageFlags,
type ChatInputApplicationCommandData,
type ChatInputCommandInteraction,
} from 'discord.js';
import { player } from './player.ts';
export interface Command {
data: ChatInputApplicationCommandData;
run(interaction: ChatInputCommandInteraction<'cached'>): Promise<unknown>;
}
const play: Command = {
data: {
name: 'play',
description: 'Play an audio file from a direct link',
options: [
{
name: 'url',
description: 'Link to an MP3, Ogg, or WAV file',
type: ApplicationCommandOptionType.String,
required: true,
},
],
},
async run(interaction) {
const channel = interaction.member.voice.channel;
if (!channel) {
return interaction.reply({ content: 'Join a voice channel first.', flags: MessageFlags.Ephemeral });
}
// Searching and connecting can take longer than Discord's 3 second reply window.
await interaction.deferReply();
const { track } = await player.play(channel, interaction.options.getString('url', true), {
requestedBy: interaction.user.id,
nodeOptions: { leaveOnEnd: true, leaveOnEndCooldown: 30_000 },
});
return interaction.editReply(track ? `Queued **${track.title}**` : 'No playable audio found at that link.');
},
};
export const commands: Command[] = [play];player.play() searches your source plugins, creates the guild's queue, joins the voice channel, and starts playback. track is null when no plugin matched the query.
Start the bot
import { Events, MessageFlags } from 'discord.js';
import { commands } from './commands.ts';
import { client, player } from './player.ts';
client.once(Events.ClientReady, async (ready) => {
await ready.application.commands.set(commands.map((command) => command.data));
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild()) return;
const command = commands.find((entry) => entry.data.name === interaction.commandName);
if (!command) return;
try {
await command.run(interaction);
} catch (error) {
console.error(`/${interaction.commandName} failed:`, error);
const reply = { content: 'Something went wrong.', flags: MessageFlags.Ephemeral } as const;
if (interaction.deferred || interaction.replied) await interaction.followUp(reply);
else await interaction.reply(reply);
}
});
player.events.on('playerStart', (queue, track) => {
console.log(`Now playing ${track.title} in ${queue.guildId}`);
});
player.events.on('playerError', (queue, error, track) => {
console.error(`Could not play ${track.title}:`, error);
});
await client.login(process.env.DISCORD_TOKEN);Run it
node --env-file=.env src/index.tsInvite the bot with the bot and applications.commands scopes and the Connect and Speak permissions. Join a voice channel and run /play with a link to an audio file.
Global slash commands can take a few minutes to appear the first time.
Continue reading
4. Control playback