Lavalink
Transformez votre bot en un DJ professionnel grâce à la puissance de l'écosystème Lavalink. Ce package utilise lavalink-client en coulisses, offrant une solution performante et efficace pour gérer les flux audio sur Discord. En tirant parti de Lavalink, votre bot acquiert la capacité de gérer la lecture audio, les files d'attente et les contrôles en temps réel avec une latence minimale, le transformant en un système musical professionnel et pleinement fonctionnel.
Installation
- npm
- Yarn
- pnpm
- Bun
npm i @necord/lavalink necord discord.js lavalink-client
yarn add @necord/lavalink necord discord.js lavalink-client
pnpm add @necord/lavalink necord discord.js lavalink-client
bun add @necord/lavalink necord discord.js lavalink-client
Utilisation
Une fois le processus d'installation terminé, nous pouvons importer le NecordLavalinkModule avec votre NecordModule dans le module racine AppModule :
import { NecordLavalinkModule } from '@necord/lavalink';
import { Module } from '@nestjs/common';
import { Client } from 'discord.js';
import { AppService } from './app.service';
@Module({
imports: [
NecordModule.forRoot({
token: process.env.DISCORD_TOKEN,
intents: [
IntentsBitField.Flags.Guilds,
IntentsBitField.Flags.GuildVoiceStates
],
}),
NecordLavalinkModule.forRoot({
// At least 1 node is required
nodes: [
{
authorization: 'youshallnotpass',
host: 'localhost',
port: 2333,
}
]
})
],
providers: [AppService]
})
export class AppModule {}
Découvrez davantage d'options de module dans la documentation officielle de lavalink-client.
Écouteurs
Dans @necord/lavalink, la gestion des événements fonctionne de la même manière que les écouteurs Necord par défaut, avec quelques changements.
- Au lieu des décorateurs
On/Oncepar défaut et deContextOf, vous pouvez utiliserOnLavalinkManager/OnceLavalinkManageretLavalinkManagerContextOfpour les événements LavalinkManager.OnNodeManager/OnceNodeManageretNodeManagerContextOfpour les événements NodeManager.
import { Injectable, Logger } from '@nestjs/common';
import { Context } from 'necord';
import { OnLavalinkManager, OnNodeManager, LavalinkManagerContextOf, NodeManagerContextOf } from '@necord/lavalink';
@Injectable()
export class AppService {
private readonly logger = new Logger(AppService.name);
@OnNodeManager('connect')
public onConnect(@Context() [node]: NodeManagerContextOf<'connect'>) {
this.logger.log(`Node: ${node.options.id} Connected`);
}
@OnLavalinkManager('playerCreate')
public onPlayerCreate(@Context() [player]: LavalinkManagerContextOf<'playerCreate'>) {
this.logger.log(`Player created at ${player.guildId}`);
}
}
Événements LavalinkManager
- Consultez la documentation officielle de lavalink-client.
| Nom de l'événement | Description |
|---|---|
trackStart | Émis chaque fois qu'une piste est lue. |
trackEnd | Émis chaque fois qu'une piste a fini d'être lue. |
trackStuck | Émis chaque fois qu'une piste se bloque pendant la lecture. |
trackError | Émis chaque fois qu'une piste rencontre une erreur. |
queueEnd | Émis lorsque la piste s'est terminée, mais qu'il n'y a plus de pistes dans la file d'attente. (trackEnd n'est PAS exécuté) |
playerCreate | Émis chaque fois qu'un lecteur est créé. |
playerMove | Émis chaque fois qu'un lecteur est déplacé entre des canaux vocaux. |
playerDisconnect | Émis chaque fois qu'un lecteur est déconnecté d'un canal. |
playerSocketClose | Émis chaque fois qu'un socket de nœud est fermé pour un lecteur spécifique. |
playerDestroy | Émis chaque fois qu'un lecteur est détruit. |
playerUpdate | Émis chaque fois qu'un lecteur reçoit une mise à jour de l'événement playerUpdate de Lavalink. |
playerMuteChange | Émis chaque fois que l'état vocal du lecteur lié à la mise en sourdine change. |
playerDeafChange | Emitted whenever Player's voice state related to deafing is changed. |
playerSuppressChange | Emitted whenever Player's voice state related to supressing is changed. |
playerQueueEmptyStart | Emitted whenever the Queue empty handler started (timeout). |
playerQueueEmptyEnd | Emitted whenever the Queue empty handler finished (successfully) and destroyed the player. |
playerQueueEmptyCancel | Emitted whenever the Queue empty handler cancelled (e.g. because a new track got added). |
playerVoiceJoin | Emitted whenever a user joins the player's voice channel. |
playerVoiceLeave | Emitted whenever a user leaves the player's voice channel. |
debug | Emitted for several erros, and logs within lavalink-client, if managerOptions.advancedOptions.enableDebugEvents is true. |
SponsorBlock Plugin Events
- This Events is a part of LavalinkManager Events.
- This requires the SponsorBlock Plugin added in Lavalink Server.
| Nom de l'événement | Description |
|---|---|
SegmentsLoaded | Emitted whenever Segments are loaded. |
SegmentSkipped | Emitted whenever a specific Segment was skipped. |
ChapterStarted | Emitted whenever a specific Chapter starts playing. |
ChaptersLoaded | Emitted whenever Chapters are loaded. |
LavaLyrics Plugin Events
- This Events is a part of LavalinkManager Events.
- This requires the LavaLyrics Plugin added in Lavalink Server.
| Nom de l'événement | Description |
|---|---|
LyricsLine | Emitted whenever a Lyrics line is received. |
LyricsFound | Emitted whenever a Lyrics is found. |
LyricsNotFound | Emitted whenever a Lyrics is not found. |
NodeManager Events
- View in Official lavalink-client Documentation.
| Nom de l'événement | Description |
|---|---|
create | Emitted whenever a Node is created. |
destroy | Emitted whenever a Node is destroyed. |
connect | Emitted whenever a Node is connected. |
reconnecting | Emitted whenever a Node is reconnecting. |
reconnectinprogress | Emitted whenever a node starts to reconnect. (if you have a reconnection delay, the reconnecting event will be emitted after the retryDelay.) Useful to check wether the internal node reconnect system works or not. |
disconnect | Emitted whenever a Node is disconnects. |
error | Emitted whenever a Node is error. |
raw | Emits every single Node event. |
Providers
@necord/lavalinkhave snippets to access the lavalink-client methods. You can inject the managers using constructor.
import { Injectable } from '@nestjs/common';
import { LavalinkManager, NodeManager } from 'lavalink-client';
@Injectable()
export class AppService {
public constructor(
private readonly lavalinkManager: LavalinkManager,
private readonly nodeManager: NodeManager,
) {}
}
| Class (Type to be injected) | Manager Property (Will access to) | Description |
|---|---|---|
LavalinkManager | lavalinkManager | Lavalink Manager |
NodeManager | lavalinkManager.nodeManager | Node Manager |
PlayerManager | lavalinkManager (player functions) | Player Manager |
Play Tracks
- Here you'll view a sample of PlayCommand using the best techniques of Slash Commands tutorial.
import { Injectable, UseInterceptors } from '@nestjs/common';
import { NecordLavalinkService, PlayerManagerService } from '@necord/lavalink';
import { Context, Options, SlashCommand, SlashCommandContext } from 'necord';
import { QueryDto } from './query.dto';
import { SourceAutocompleteInterceptor } from 'source.autocomplete';
@Injectable()
export class AppCommands {
public constructor(
private readonly playerManager: PlayerManagerService,
private readonly lavalinkService: NecordLavalinkService
) {}
@UseInterceptors(SourceAutocompleteInterceptor)
@SlashCommand({
name: 'play',
description: 'play a track',
})
public async onPlay(
@Context() [interaction]: SlashCommandContext,
@Options() { query, source }: QueryDto,
) {
const player =
this.playerManager.get(interaction.guild.id) ??
this.playerManager.create({
...this.lavalinkService.extractInfoForPlayer(interaction),
// optional configurations:
selfDeaf: true,
selfMute: false,
volume: 100,
});
await player.connect();
const res = await player.search(
{
query,
source: source ?? 'soundcloud'
},
interaction.user.id,
);
await player.queue.add(res.tracks[0]);
if (!player.playing) await player.play();
// It's extremely recommended to use `trackStart` event for this announcement
return interaction.reply({
content: `Now playing ${res.tracks[0].info.title}`,
});
}
}
import { SearchPlatform } from 'lavalink-client';
import { StringOption } from 'necord';
export class QueryDto {
@StringOption({
name: 'query',
description: '<name | url> of the requested track',
required: true
})
public readonly query!: string;
@StringOption({
name: 'source',
description: 'source of the track',
autocomplete: true,
required: false,
})
public readonly source?: SearchPlatform;
}
import { Injectable } from '@nestjs/common';
import { AutocompleteInteraction } from 'discord.js';
import { DefaultSources } from 'lavalink-client';
import { AutocompleteInterceptor } from 'necord';
@Injectable()
export class SourceAutocompleteInterceptor extends AutocompleteInterceptor {
public transformOptions(interaction: AutocompleteInteraction) {
const focused = interaction.options.getFocused(true);
let choices: string[];
if (focused.name === 'source') {
choices = [DefaultSources.soundcloud] // Note that some Sources needs extra plugins/configuration to property work
}
return interaction.respond(
choices
.filter((choice) => choice.startsWith(focused.value.toString()))
.map((choice) => ({ name: choice, value: choice })),
);
}
}
You can view a working example here.