Skip to content

NodeLink Support

NodeLink is a Node.js-based Lavalink alternative. Ryanlink has full NodeLink support via the NodeLinkNode class, which extends RyanlinkNode with all NodeLink-exclusive endpoints.

Set nodeType: 'NodeLink' in your node configuration:

const manager = new RyanlinkManager({
nodes: [{
id: 'nodelink-main',
host: 'localhost',
port: 3000,
authorization: 'youshallnotpass',
nodeType: 'NodeLink',
}],
// ...
});
import { NodeLinkNode } from 'ryanlink';
if (player.node.isNodeLink()) {
const nodeLinkNode = player.node as NodeLinkNode;
}

Audio Mixer NodeLink only

Section titled “Audio Mixer ”

Overlay TTS, SFX, or background music on top of the main track.

const node = player.node as NodeLinkNode;
// Add a mix layer (volume 0–100)
const layer = await node.addMixerLayer(player, ttsTrack, 90);
// layer.id, layer.track, layer.volume
// List active layers
const layers = await node.listMixerLayers(player);
// layers.mixes[] — { id, track, volume, position, startTime }
// Update volume
await node.updateMixerLayerVolume(player, layer.id, 50);
// Remove
await node.removeMixerLayer(player, layer.id);

Fading NodeLink only

Section titled “Fading ”

Smooth volume transitions for track changes, seeking, and pausing.

await node.setFading(player, {
enabled: true,
trackStart: { duration: 1500, curve: 's-curve' },
trackEnd: { duration: 1000, curve: 'linear' },
seek: { duration: 500, curve: 'linear' },
stop: { duration: 800, curve: 'exponential' },
ducking: { volume: 0.3, duration: 300, curve: 'exponential' },
});

Supported curves: linear, exponential, logarithmic, s-curve.


Gapless Preloading NodeLink only

Section titled “Gapless Preloading ”

Pre-load the next track while the current one is still playing.

// Pre-load next track from queue
await node.setNextTrackGapLess(player);
// Or specify a track explicitly
await node.setNextTrackGapLess(player, specificTrack);
// Remove preloaded track
await node.removeNextTrackGapLess(player);

Lyrics NodeLink only

Section titled “Lyrics ”
const lyrics = await node.loadLyrics(track, 'en');
// Returns NodeLinkLyrics | NodeLinkNoLyrics
// lyrics.data.synced — boolean
// lyrics.data.lines[] — { text, time, duration }
// lyrics.data.source — provider name
const chapters = await node.loadChapters(track);
// Returns NodeLinkChapter[] | { loadType: 'empty' }
// chapter.title, chapter.startTime, chapter.endTime, chapter.duration
const lyrics = await node.nodeLinkLyrics(player, track, 'en');
// Uses player.queue.current if track is not provided
await node.subscribeLyricsNodeLink(player);
await node.subscribeLyricsNodeLink(player, true); // skipTrackSource
await node.unsubscribeLyricsNodeLink(player);
const chapters = await node.getChapters(player, track);
// Uses player.queue.current if track is not provided

timedLyrics (lyrics.kt / java-timed-lyrics)

Section titled “timedLyrics (lyrics.kt / java-timed-lyrics)”
const result = await node.timedLyrics.getCurrent(player.guildId);
const result2 = await node.timedLyrics.getByVideoId('dQw4w9WgXcQ');
const results = await node.timedLyrics.search('never gonna give you up');
const genius = await node.timedLyrics.search('never gonna give you up', 'genius');

Meaning NodeLink only

Section titled “Meaning ”

Wikipedia/Letras background info for a track or artist.

const meaning = await node.getMeaning(track, 'en');
// meaning.data.title, .description, .paragraphs[], .url, .provider, .type

Direct Streaming NodeLink only

Section titled “Direct Streaming ”
const stream = await node.getDirectStream(track);
// stream.url — direct audio URL
// stream.formats[] — { itag, mimeType, qualityLabel, bitrate }
// With specific itag
const stream2 = await node.getDirectStream(track, 251);
const pcmStream = await node.loadDirectStream(track, 100, 30000, { equalizer: [] });
// Returns ReadableStream
const pcmStream2 = await node.loadDirectStreamPost(track, 100, 30000, { equalizer: [] });
// Returns ReadableStream

Track Encoding NodeLink only

Section titled “Track Encoding ”
// Encode a single track object to base64
const encoded = await node.encodeTrack({ identifier: 'dQw4w9WgXcQ', title: '...', /* ... */ });
// encoded.encoded — base64 string
// Encode multiple tracks
const encodedList = await node.encodeTracks([track1Info, track2Info]);
// encodedList[] — { encoded: string | null, error?: string }

YouTube Config NodeLink only

Section titled “YouTube Config ”
// Update OAuth/visitorData live (no restart needed)
await node.updateYoutubeConfig('1//0gN...refreshToken', 'Cgt...visitorData');
// Get current config
const config = await node.getYoutubeConfig();
// config.refreshToken, .visitorData, .isConfigured, .isValid
// Validate token with Google
const validated = await node.getYoutubeConfig(true);
// Exchange refresh token for access token
const oauth = await node.getYoutubeOAUTH(refreshToken);
// oauth.access_token, .expires_in, .scope, .token_type
// POST variant
const oauth2 = await node.updateYoutubeOAUTH(refreshToken);

Cluster Workers NodeLink only

Section titled “Cluster Workers ”
// Get all worker metrics
const workers = await node.getWorkers();
// workers.workers[] — { id, clusterId, pid, status, players, uptime, memory }
// workers.total — number
// Terminate/restart a worker
await node.patchWorker('ADMIN_CODE', { id: 1 });
await node.patchWorker('ADMIN_CODE', { pid: 24560 });
await node.patchWorker('ADMIN_CODE', { clusterId: 0 });

Multi-Audio Track (Dubs) NodeLink only

Section titled “Multi-Audio Track (Dubs) ”

When loading a track, pluginInfo.audioTracks contains available audio streams:

const result = await manager.search({ query: 'https://youtube.com/...' }, user);
const track = result.tracks[0];
// Check available audio tracks
console.log(track.pluginInfo.audioTracks);
// [{ id: 'en', name: 'English (Original)', isDefault: true, isAutoDubbed: false }, ...]
// Select a specific audio track language
await node.changeAudioTrackLanguage(player, 'pt-br');

Section titled “NodeLink Stats ”
// Detailed stats with per-source and per-endpoint tracking
const stats = await node.getDetailedStats();
// stats.players, .playingPlayers, .uptime, .memory, .cpu, .frameStats, .detailedStats
// NodeLink info
const info = await node.getNodeLinkInfo();
// info.version, .buildTime, .git, .sourceManagers, .filters, .plugins
// Connection metrics
const metrics = await node.getConnectionMetrics();
// metrics.status, .metrics.speed, .metrics.downloadedBytes

Section titled “NodeLink-Exclusive Filters ”
const node = player.node as NodeLinkNode;
await node.specificFilters.echo(player, { delay: 0.5, feedback: 0.3, mix: 0.5 });
await node.specificFilters.chorus(player, { rate: 1.0, depth: 0.5, delay: 0.02, mix: 0.5, feedback: 0.3 });
await node.specificFilters.compressor(player, { threshold: -20, ratio: 4, attack: 5, release: 50, gain: 0 });
await node.specificFilters.highPass(player, { smoothing: 20 });
await node.specificFilters.phaser(player, { stages: 4, rate: 0.5, depth: 0.5, feedback: 0.3, mix: 0.5, minFrequency: 300, maxFrequency: 3000 });
await node.specificFilters.spatial(player, { depth: 0.5, rate: 0.5 });
// Disable a filter
await node.specificFilters.echo(player, {}, true);
// Reset all NodeLink filters
await node.specificFilters.resetNodeLinkFilters(player);