Star ✨ on GitHub

Basic Setup

Configure Moonlink.js with your Discord bot for music playback

Prerequisites

Before proceeding, ensure you have:

  • Installed Moonlink.js and its dependencies.
  • A running Lavalink instance (see Lavalink Documentation).
  • A configured Discord bot with the necessary intents enabled.

1. Creating the Manager Instance

Moonlink.js uses a Manager to handle connections to Lavalink, create players, and manage events. Create a new instance by providing your Lavalink node configuration and a function to forward voice state updates.

Example (JavaScript)

const { Client, GatewayIntentBits } = require('discord.js');
const { Manager } = require('moonlink.js');

// Initialize Discord client with required intents
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildVoiceStates,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

// Create the Moonlink Manager
const manager = new Manager({
  nodes: [
    {
      host: 'localhost',    // Lavalink host
      port: 2333,           // Lavalink port
      password: 'youshallnotpass', // Lavalink password
      secure: false,
    },
  ],
  sendPayload: (guildId, payload) => {
    const guild = client.guilds.cache.get(guildId);
    if (guild) guild.shard.send(JSON.parse(payload));
  },
});

// Attach the manager to your client for easy access
client.manager = manager;

Example (TypeScript)

import { Client, GatewayIntentBits } from 'discord.js';
import { Manager } from 'moonlink.js';

// Initialize Discord client with required intents
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildVoiceStates,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

// Create the Moonlink Manager
const manager = new Manager({
  nodes: [
    {
      host: 'localhost',
      port: 2333,
      password: 'youshallnotpass',
      secure: false,
    },
  ],
  sendPayload: (guildId: string, payload: object) => {
    const guild = client.guilds.cache.get(guildId);
    if (guild) guild.shard.send(JSON.parse(payload));
  },
});

// Attach the manager to the client
(client as any).manager = manager;

2. Initializing the Manager

Once your bot is ready, initialize the Manager to connect to your Lavalink nodes. This step should occur once your client is logged in.

client.once('ready', () => {
  console.log(`Logged in as ${client.user.tag}`);
  client.manager.init(client.user.id);
});

3. Handling Voice State Updates

For Moonlink.js to function correctly with Discord’s voice system, forward all raw voice state packets:

client.on('raw', (packet) => {
  client.manager.packetUpdate(packet);
});

4. Basic Event Handling

Moonlink.js emits several events for both node and player status. Here’s how to listen for some common events:

// Node events
client.manager.on('nodeConnect', (node) => {
  console.log(`Node ${node.identifier} connected!`);
});

client.manager.on('nodeDisconnect', (node) => {
  console.log(`Node ${node.identifier} disconnected!`);
});

client.manager.on('nodeError', (node, error) => {
  console.error(`Node ${node.identifier} encountered an error:`, error);
});

// Player events
client.manager.on('trackStart', (player, track) => {
  const channel = client.channels.cache.get(player.textChannelId);
  if (channel) channel.send(`Now playing: **${track.title}**`);
});

client.manager.on('queueEnd', (player) => {
  const channel = client.channels.cache.get(player.textChannelId);
  if (channel) channel.send('Queue ended!');
  
  // Optionally disconnect after a delay
  setTimeout(() => {
    if (!player.playing && player.queue.size === 0) {
      player.destroy();
      if (channel) channel.send('Disconnected due to inactivity.');
    }
  }, 30000); // 30 seconds
});

5. Complete Example

Below is a consolidated example that brings all the pieces together for a basic music bot setup using Moonlink.js.

const { Client, GatewayIntentBits } = require('discord.js');
const { Manager } = require('moonlink.js');

// Initialize Discord client
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildVoiceStates,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

// Create Moonlink Manager with your Lavalink node settings
client.manager = new Manager({
  nodes: [
    {
      host: 'localhost',
      port: 2333,
      password: 'youshallnotpass',
      secure: false,
      identifier: 'Main Node',
    },
  ],
  sendPayload: (guildId, payload) => {
    const guild = client.guilds.cache.get(guildId);
    if (guild) guild.shard.send(JSON.parse(payload));
  },
  defaultVolume: 100,
  autoPlay: true,
});

// Initialize the manager when the client is ready
client.once('ready', () => {
  console.log(`Logged in as ${client.user.tag}`);
  client.manager.init(client.user.id);
});

// Forward raw packets for voice updates
client.on('raw', (packet) => {
  client.manager.packetUpdate(packet);
});

// Handle node events
client.manager.on('nodeConnect', (node) => console.log(`Node ${node.identifier} connected!`));
client.manager.on('nodeError', (node, error) => console.error(`Node ${node.identifier} error:`, error));

// Example command to play a track (basic implementation)
client.on('messageCreate', async (message) => {
  if (message.author.bot || !message.guild) return;

  if (message.content.startsWith('!play')) {
    const voiceChannel = message.member.voice.channel;
    if (!voiceChannel) return message.reply('You need to be in a voice channel!');

    const query = message.content.replace('!play', '').trim();
    if (!query) return message.reply('Please specify a song to play.');

    const player = client.manager.createPlayer({
      guildId: message.guild.id,
      voiceChannelId: voiceChannel.id,
      textChannelId: message.channel.id,
      autoPlay: true,
    });
    
    player.connect();
    
    const result = await client.manager.search({
      query
    });
    if (!result.tracks.length) return message.reply('No results found!');
    
    player.queue.add(result.tracks[0]);
    if (!player.playing) player.play();

    message.reply(`Added to queue: **${result.tracks[0].title}**`);
  }
});

// Log in to Discord
client.login('YOUR_BOT_TOKEN');