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.
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.