aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord-Bots

Discord-Musikbot bauen mit discord.js und Lavalink

Einen Discord-Musikbot zu schreiben wirkt auf den ersten Blick einfach — „betritt einen Kanal, spiele einen Song" — doch es wird ernst, sobald solide Warteschlangenverwaltung, unterbrechungsfreies Audio-Streaming und eine Architektur dazukommen, die auf vielen Servern gleichzeitig läuft. In dieser Anleitung bauen wir einen modernen Bot in zwei Schichten: discord.js für die Bot-Logik und einen separaten Audioserver, Lavalink, für Dekodierung und Streaming. Den direkten Ansatz mit @discordjs/voice für kleinere Bots streifen wir ebenfalls kurz.

Warum Lavalink? Der Unterschied zu @discordjs/voice

@discordjs/voice ist die offizielle Bibliothek, mit der dein Bot einen Sprachkanal betreten und einen rohen PCM/Opus-Stream senden kann. Für sich genommen reicht sie zum Musikabspielen aus: Du holst eine Stream-Quelle (etwa ytdl-core oder play-dl), wandelst sie mit createAudioResource in eine Ressource um und spielst sie über einen AudioPlayer ab. Das Problem dieses Ansatzes ist die Skalierung: Dekodierung und Transkodierung von Audio belasten denselben Node-Prozess, in dem dein Bot läuft, stark.

Lavalink hingegen ist ein eigenständiger, Java-basierter Audio-Node, der diese schwere Arbeit übernimmt. Dein Bot sagt Lavalink über einen WebSocket „spiele diesen Track in diesem Kanal", und Lavalink erledigt die gesamte Dekodierung und das Streaming. Die Vorteile:

  • Die CPU-Last wird vom Bot ausgelagert; ein einzelner Node kann Hunderte Server bedienen.
  • Integrierte Plugin-Unterstützung für YouTube, SoundCloud, Bandcamp, Twitch und HTTP-Quellen.
  • Sitzungskontinuität und robuste Wiederverbindung, selbst wenn der Bot neu startet.

Für einen kleinen Hobby-Bot auf einem einzigen Server reicht @discordjs/voice völlig aus. Wenn du rund um die Uhr auf vielen Servern abspielen willst, ist Lavalink nahezu Pflicht.

Das Projekt aufsetzen und den Bot registrieren

Initialisiere zunächst ein Node.js-Projekt (Node 18+ empfohlen) und installiere die nötigen Pakete:

mkdir musik-bot && cd musik-bot
npm init -y
npm install discord.js shoukaku dotenv

Hier ist shoukaku eine ausgereifte Client-Bibliothek, die zwischen discord.js und Lavalink vermittelt (Alternativen: lavalink-client, das anstelle von erela.js aktiv gepflegt wird). Erstelle eine Anwendung im Discord Developer Portal, hol dir ein Bot-Token und trage es in eine .env-Datei ein. Erteile beim Einladen des Bots die Scopes bot und applications.commands sowie die Sprachrechte Connect und Speak.

Den Lavalink-Node betreiben

Lavalink wird als ausführbares JAR ausgeliefert und benötigt Java 17+. Lade die offizielle Version herunter und lege eine application.yml daneben:

server:
  port: 2333
lavalink:
  server:
    password: "ein-starkes-passwort"

Starte es dann mit java -jar Lavalink.jar. In aktuellen Versionen musst du für die YouTube-Quelle eventuell ein separates Plugin (etwa youtube-source) konfigurieren; prüfe die Startlogs, um zu sehen, welche Quellen geladen wurden. Im Produktivbetrieb machst du diesen Prozess mit systemd oder Docker dauerhaft.

Den Bot mit Lavalink verbinden

Mit Shoukaku richtest du die Node-Verbindung und einen Basis-Client so ein:

const { Client, GatewayIntentBits } = require('discord.js');
const { Shoukaku, Connectors } = require('shoukaku');
require('dotenv').config();

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildVoiceStates,
  ],
});

const nodes = [{
  name: 'main',
  url: 'localhost:2333',
  auth: process.env.LAVALINK_PASSWORD,
}];

const shoukaku = new Shoukaku(new Connectors.DiscordJS(client), nodes);
shoukaku.on('error', (_, err) => console.error(err));

client.login(process.env.DISCORD_TOKEN);

Hinweis: Der Intent GuildVoiceStates ist erforderlich, um Sprachzustände zu verfolgen. Ohne ihn kann der Bot nicht sehen, in welchem Kanal sich ein Nutzer befindet.

Die Abspiel-Warteschlange bauen

Das eigentliche Musikerlebnis bestimmt die „Warteschlange": gleichzeitige Anfragen einreihen, nach einem Track automatisch weiterschalten und den Kanal verlassen, wenn er sich leert. Halte pro Server eine eigene Warteschlange. Ein einfacher play-Ablauf:

async function play(interaction, query) {
  const node = shoukaku.options.nodeResolver(shoukaku.nodes);
  const result = await node.rest.resolve(`ytsearch:${query}`);
  if (!result || !result.data.length) {
    return interaction.reply('Keine Ergebnisse gefunden.');
  }
  const track = result.data[0];

  const player = await shoukaku.joinVoiceChannel({
    guildId: interaction.guildId,
    channelId: interaction.member.voice.channelId,
    shardId: 0,
  });

  player.playTrack({ track: { encoded: track.encoded } });
  return interaction.reply(`Spielt jetzt: **${track.info.title}**`);
}

In einem echten Bot kapselst du das in eine Warteschlangen-Klasse: Beim Ereignis player.on('end', ...) ziehst du den nächsten Track aus dem Array und spielst ihn ab, und wenn das Array leer ist, verlässt du den Kanal nach einer Schonfrist mit shoukaku.leaveVoiceChannel. Die Warteschlange als Map<guildId, Queue> im Speicher zu halten, reicht für die meisten Bots.

Slash-Befehle hinzufügen

Moderne Discord-Bots nutzen Slash-Befehle statt Text-Trigger. Registriere die Befehle einmal über REST und verarbeite sie im interactionCreate-Ereignis:

const { SlashCommandBuilder, REST, Routes } = require('discord.js');

const commands = [
  new SlashCommandBuilder()
    .setName('play')
    .setDescription('Einen Song abspielen')
    .addStringOption(o =>
      o.setName('query').setDescription('Songname oder URL').setRequired(true)),
].map(c => c.toJSON());

const rest = new REST().setToken(process.env.DISCORD_TOKEN);
await rest.put(
  Routes.applicationCommands(process.env.CLIENT_ID),
  { body: commands },
);

Füge skip, queue, pause, stop und volume auf dieselbe Weise hinzu. Jeder Befehl außer play liest und aktualisiert den Warteschlangenzustand; deinen Warteschlangen-Manager in einem einzigen Modul zu bündeln, macht den Code deshalb deutlich wartbarer.

Häufige Fehler

  • Bot betritt den Kanal, aber kein Ton: Meist kann der Lavalink-Node die Quelle nicht auflösen. Prüfe die Node-Logs und ob das Quellen-Plugin geladen wurde.
  • „Used disallowed intents": Du hast vergessen, die betreffenden Intents im Developer Portal zu aktivieren.
  • Bot eingeladen, aber Befehle erscheinen nicht: Globale Befehle brauchen Zeit zur Verbreitung; während der Entwicklung funktioniert die Registrierung auf einem bestimmten Server (Guild) sofort.

Häufig gestellte Fragen

Ist Lavalink Pflicht, oder reicht reines discord.js?

Für einen einzigen Server mit gelegentlicher Wiedergabe genügt @discordjs/voice plus eine Quelle wie play-dl. Wenn du durchgehend auf vielen Servern abspielst, bietet Lavalink ein weitaus stabileres Erlebnis, weil es die CPU-Last vom Bot auslagert.

Gibt es beim Urheberrecht etwas zu beachten?

Audioquellen und die Nutzungsbedingungen der Plattformen ändern sich im Lauf der Zeit. Stelle bei einem kommerziellen oder groß angelegten Projekt sicher, dass die abgespielten Inhalte den Bedingungen der jeweiligen Plattform entsprechen, und bevorzuge nach Möglichkeit lizenzierte APIs.

Wo sollte ich den Bot hosten?

Für geringe Latenz betreibst du Bot und Lavalink-Node am besten auf einem VPS in derselben Region. Kostenlose Plattformen, die „in den Ruhezustand" gehen, eignen sich nicht für Musikbots; du brauchst einen durchgehend laufenden Server.

Möchtest du deinen eigenen Musikbot? Für einen maßgeschneiderten, von Anfang bis Ende aufgebauten Bot mit Warteschlangenverwaltung, Slash-Befehlen und Lavalink-Infrastruktur nimm Kontakt mit mir auf.

Devamı için