Skip to main content
Version: v2.10.3 (current)

Lyrics, Chapters, and SponsorBlock

Lyricsโ€‹

On Lavalink, lyrics need a supported plugin. NodeLink exposes a native load endpoint, so no JVM lyrics plugin is required.

const current = await player.queue.getCurrent();
if (current) {
const lyrics = await player.node.getLyrics(current, false, "en");
if ("loadType" in lyrics) {
// NodeLink result.
if (lyrics.loadType === "lyrics") {
console.log(lyrics.data.lines?.map((line) => line.text));
}
} else {
// Lavalink/plugin result.
console.log(lyrics.lines.map((line) => line.line));
}
}

node.getLyrics(track, skipTrackSource?, language?) returns Lyrics or NodeLinkGetLyrics. The language parameter is sent to NodeLink's native load endpoint. Current NodeLink lines use time and text; legacy result variants are still in the union.

warning

player.getCurrentLyrics() currently declares Promise<Lyrics> but does not normalize NodeLink's native result. On NodeLink, use node.getLyrics() and narrow the returned union as above instead of assuming normalized fields.

Live Lyricsโ€‹

import { ManagerEventTypes } from "magmastream";

await player.node.lyricsSubscribe(player.guildId);

manager.on(ManagerEventTypes.LyricsLine, (eventPlayer, track, payload) => {
if (eventPlayer.guildId !== player.guildId) return;
console.log(payload.line);
});

await player.node.lyricsUnsubscribe(player.guildId);

The helpers use NodeLink's player-scoped subscribe route or the supported Lavalink plugin route. The current subscription helper does not expose a language argument. Callbacks also include lyricsFound and lyricsNotFound; their track argument can be null.

Live-event lyrics use the event/plugin schema, not the native load result's time / text schema. See Lyrics Events.

Chaptersโ€‹

const current = await player.queue.getCurrent();
if (player.node.isNodeLink && current) {
const chapters = await player.getNodeLinkChapters(current);
for (const chapter of chapters) {
console.log(chapter.title, chapter.startTime);
}
}

getChapters(track?) is an equivalent NodeLink-only alias. Omit the track to use the current track; the helper rejects if neither is available. node.getNodeLinkChapters(track) accepts an explicit track. Timestamps use milliseconds; not every source supplies chapters.

chaptersLoaded and chapterStarted are manager callbacks with a nullable track. Lavalink plugin chapter events remain supported separately; that does not make the native chapter-loading helper available on Lavalink.

Meaning and Backgroundโ€‹

const current = await player.queue.getCurrent();
if (player.node.isNodeLink && current) {
const meaning = await player.getNodeLinkMeaning(current, "en");
console.log(meaning);
}

This uses NodeLink's meaning endpoint and returns NodeLinkMeaningResult. An explicit track can replace undefined.

SponsorBlock Categoriesโ€‹

The existing category helpers select the backend-specific endpoint:

import { SponsorBlockSegment } from "magmastream";

await player.setSponsorBlock([
SponsorBlockSegment.Sponsor,
SponsorBlockSegment.SelfPromo,
]);

const enabledCategories = await player.getSponsorBlock();
await player.deleteSponsorBlock();

Lavalink requires the SponsorBlock plugin. NodeLink uses native player settings. The result above is a list of category enum values, not full segment objects.

Native State and Settingsโ€‹

if (player.node.isNodeLink) {
await player.updateNodeLinkSponsorBlock({
enabled: true,
categories: ["sponsor", "selfpromo"],
actionTypes: ["skip"],
skipMarginMs: 100,
});

const state = await player.getNodeLinkSponsorBlockState();
console.log(state);
}

For replacing explicit segment data, call player.setNodeLinkSponsorBlockSegments(segments). Its input is NodeLinkSponsorBlockSegment[], not the category enum array. Required fields include UUID, start/end, category, action type, votes, lock state, video duration, and description. Segment timestamps are milliseconds.

The same helpers exist on Node, with the player as their first argument. segmentsLoaded and segmentSkipped callbacks can have a null track.