lavalink-client 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,10 +6,6 @@ import { DestroyReasonsType, Player, PlayerJson, PlayerOptions } from "./Player"
6
6
  import { ManagerQueueOptions } from "./Queue";
7
7
  import { Track, UnresolvedTrack } from "./Track";
8
8
  import { ChannelDeletePacket, GuildShardPayload, ManagerUtils, MiniMap, SearchPlatform, SponsorBlockChaptersLoaded, SponsorBlockChapterStarted, SponsorBlockSegmentSkipped, SponsorBlockSegmentsLoaded, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, VoicePacket, VoiceServer, VoiceState, WebSocketClosedEvent } from "./Utils";
9
- export interface LavalinkManager {
10
- nodeManager: NodeManager;
11
- utils: ManagerUtils;
12
- }
13
9
  export interface BotClientOptions {
14
10
  /** Bot Client Id */
15
11
  id: string;
@@ -168,31 +164,186 @@ interface LavalinkManagerEvents {
168
164
  "ChaptersLoaded": (player: Player, track: Track | UnresolvedTrack, payload: SponsorBlockChaptersLoaded) => void;
169
165
  }
170
166
  export interface LavalinkManager {
171
- options: ManagerOptions;
167
+ /** @private */
172
168
  on<U extends keyof LavalinkManagerEvents>(event: U, listener: LavalinkManagerEvents[U]): this;
169
+ /** @private */
173
170
  emit<U extends keyof LavalinkManagerEvents>(event: U, ...args: Parameters<LavalinkManagerEvents[U]>): boolean;
174
171
  }
175
172
  export declare class LavalinkManager extends EventEmitter {
176
- static DefaultSources: Record<SearchPlatform, import("./Utils").LavalinkSearchPlatform | import("./Utils").ClientCustomSearchPlatformUtils>;
177
- static SourceLinksRegexes: Record<import("./Utils").SourcesRegex, RegExp>;
173
+ /** The Options of LavalinkManager (changeable) */
174
+ options: ManagerOptions;
175
+ /** LavalinkManager's NodeManager to manage all Nodes */
176
+ nodeManager: NodeManager;
177
+ /** LavalinkManager's Utils Class */
178
+ utils: ManagerUtils;
179
+ /** Wether the manager was initiated or not */
178
180
  initiated: boolean;
181
+ /** All Players stored in a MiniMap */
179
182
  readonly players: MiniMap<string, Player>;
183
+ /**
184
+ * Applies the options provided by the User
185
+ * @param options
186
+ * @returns
187
+ */
180
188
  private applyOptions;
189
+ /**
190
+ * Validates the current manager's options
191
+ * @param options
192
+ */
181
193
  private validateOptions;
194
+ /**
195
+ * Create the Lavalink Manager
196
+ * @param options
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * //const client = new Client({...}); // create your BOT Client (e.g. via discord.js)
201
+ * client.lavalink = new LavalinkManager({
202
+ * nodes: [
203
+ * {
204
+ * authorization: "yourverystrongpassword",
205
+ * host: "localhost",
206
+ * port: 2333,
207
+ * id: "testnode"
208
+ * },
209
+ * sendToShard(guildId, payload) => client.guilds.cache.get(guildId)?.shard?.send(payload),
210
+ * client: {
211
+ * id: process.env.CLIENT_ID,
212
+ * username: "TESTBOT"
213
+ * },
214
+ * // optional Options:
215
+ * autoSkip: true,
216
+ * playerOptions: {
217
+ * applyVolumeAsFilter: false,
218
+ * clientBasedPositionUpdateInterval: 150,
219
+ * defaultSearchPlatform: "ytmsearch",
220
+ * volumeDecrementer: 0.75,
221
+ * //requesterTransformer: YourRequesterTransformerFunction,
222
+ * onDisconnect: {
223
+ * autoReconnect: true,
224
+ * destroyPlayer: false
225
+ * },
226
+ * onEmptyQueue: {
227
+ * destroyAfterMs: 30_000,
228
+ * //autoPlayFunction: YourAutoplayFunction,
229
+ * },
230
+ * useUnresolvedData: true
231
+ * },
232
+ * queueOptions: {
233
+ * maxPreviousTracks: 25,
234
+ * //queueStore: yourCustomQueueStoreManagerClass,
235
+ * //queueChangesWatcher: yourCustomQueueChangesWatcherClass
236
+ * },
237
+ * linksBlacklist: [],
238
+ * linksWhitelist: [],
239
+ * advancedOptions: {
240
+ * debugOptions: {
241
+ * noAudio: false,
242
+ * playerDestroy: {
243
+ * dontThrowError: false,
244
+ * debugLogs: false
245
+ * }
246
+ * }
247
+ * }
248
+ * ]
249
+ * })
250
+ * ```
251
+ */
182
252
  constructor(options: ManagerOptions);
183
- createPlayer(options: PlayerOptions): Player;
253
+ /**
254
+ * Get a Player from Lava
255
+ * @param guildId The guildId of the player
256
+ *
257
+ * @example
258
+ * ```ts
259
+ * const player = client.lavalink.getPlayer(interaction.guildId);
260
+ * ```
261
+ * A quicker and easier way than doing:
262
+ * ```ts
263
+ * const player = client.lavalink.players.get(interaction.guildId);
264
+ * ```
265
+ * @returns
266
+ */
184
267
  getPlayer(guildId: string): Player;
268
+ /**
269
+ * Create a Music-Player. If a player exists, then it returns it before creating a new one
270
+ * @param options
271
+ * @returns
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * const player = client.lavalink.createPlayer({
276
+ * guildId: interaction.guildId,
277
+ * voiceChannelId: interaction.member.voice.channelId,
278
+ * // everything below is optional
279
+ * textChannelId: interaction.channelId,
280
+ * volume: 100,
281
+ * selfDeaf: true,
282
+ * selfMute: false,
283
+ * instaUpdateFiltersFix: true,
284
+ * applyVolumeAsFilter: false
285
+ * //only needed if you want to autopick node by region (configured by you)
286
+ * // vcRegion: interaction.member.voice.rtcRegion,
287
+ * // provide a specific node
288
+ * // node: client.lavalink.nodeManager.leastUsedNodes("memory")[0]
289
+ * });
290
+ * ```
291
+ */
292
+ createPlayer(options: PlayerOptions): Player;
293
+ /**
294
+ * Destroy a player with optional destroy reason and disconnect it from the voice channel
295
+ * @param guildId
296
+ * @param destroyReason
297
+ * @returns
298
+ *
299
+ * @example
300
+ * ```ts
301
+ * client.lavalink.destroyPlayer(interaction.guildId, "forcefully destroyed the player");
302
+ * // recommend to do it on the player tho: player.destroy("forcefully destroyed the player");
303
+ * ```
304
+ */
185
305
  destroyPlayer(guildId: string, destroyReason?: string): Promise<Player>;
306
+ /**
307
+ * Delete's a player from the cache without destroying it on lavalink (only works when it's disconnected)
308
+ * @param guildId
309
+ * @returns
310
+ */
186
311
  deletePlayer(guildId: string): boolean;
312
+ /**
313
+ * Checks wether the the lib is useable based on if any node is connected
314
+ */
187
315
  get useable(): boolean;
188
316
  /**
189
- * Initiates the Manager.
317
+ * Initiates the Manager, creates all nodes and connects all of them
190
318
  * @param clientData
319
+ *
320
+ * @example
321
+ *
322
+ * ```ts
323
+ * // on the bot ready event
324
+ * client.on("ready", () => {
325
+ * client.lavalink.init({
326
+ * id: client.user.id,
327
+ * username: client.user.username
328
+ * });
329
+ * });
330
+ * ```
191
331
  */
192
332
  init(clientData: BotClientOptions): Promise<this>;
193
333
  /**
194
334
  * Sends voice data to the Lavalink server.
335
+ * ! Without this the library won't work
195
336
  * @param data
337
+ *
338
+ * @example
339
+ *
340
+ * ```ts
341
+ * // on the bot "raw" event
342
+ * client.on("raw", (d) => {
343
+ * // required in order to send audio updates and register channel deletion etc.
344
+ * client.lavalink.sendRawData(d)
345
+ * })
346
+ * ```
196
347
  */
197
348
  sendRawData(data: VoicePacket | VoiceServer | VoiceState | ChannelDeletePacket): Promise<void>;
198
349
  }
@@ -1,14 +1,24 @@
1
1
  import { EventEmitter } from "events";
2
- import { DefaultSources, SourceLinksRegexes } from "./LavalinkManagerStatics";
3
2
  import { NodeManager } from "./NodeManager";
4
3
  import { DestroyReasons, Player } from "./Player";
5
4
  import { DefaultQueueStore } from "./Queue";
6
5
  import { ManagerUtils, MiniMap } from "./Utils";
7
6
  export class LavalinkManager extends EventEmitter {
8
- static DefaultSources = DefaultSources;
9
- static SourceLinksRegexes = SourceLinksRegexes;
7
+ /** The Options of LavalinkManager (changeable) */
8
+ options;
9
+ /** LavalinkManager's NodeManager to manage all Nodes */
10
+ nodeManager;
11
+ /** LavalinkManager's Utils Class */
12
+ utils;
13
+ /** Wether the manager was initiated or not */
10
14
  initiated = false;
15
+ /** All Players stored in a MiniMap */
11
16
  players = new MiniMap();
17
+ /**
18
+ * Applies the options provided by the User
19
+ * @param options
20
+ * @returns
21
+ */
12
22
  applyOptions(options) {
13
23
  this.options = {
14
24
  client: {
@@ -56,6 +66,10 @@ export class LavalinkManager extends EventEmitter {
56
66
  };
57
67
  return;
58
68
  }
69
+ /**
70
+ * Validates the current manager's options
71
+ * @param options
72
+ */
59
73
  validateOptions(options) {
60
74
  if (typeof options?.sendToShard !== "function")
61
75
  throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
@@ -86,6 +100,64 @@ export class LavalinkManager extends EventEmitter {
86
100
  if (typeof options?.queueOptions?.maxPreviousTracks !== "number" || options?.queueOptions?.maxPreviousTracks < 0)
87
101
  options.queueOptions.maxPreviousTracks = 25;
88
102
  }
103
+ /**
104
+ * Create the Lavalink Manager
105
+ * @param options
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * //const client = new Client({...}); // create your BOT Client (e.g. via discord.js)
110
+ * client.lavalink = new LavalinkManager({
111
+ * nodes: [
112
+ * {
113
+ * authorization: "yourverystrongpassword",
114
+ * host: "localhost",
115
+ * port: 2333,
116
+ * id: "testnode"
117
+ * },
118
+ * sendToShard(guildId, payload) => client.guilds.cache.get(guildId)?.shard?.send(payload),
119
+ * client: {
120
+ * id: process.env.CLIENT_ID,
121
+ * username: "TESTBOT"
122
+ * },
123
+ * // optional Options:
124
+ * autoSkip: true,
125
+ * playerOptions: {
126
+ * applyVolumeAsFilter: false,
127
+ * clientBasedPositionUpdateInterval: 150,
128
+ * defaultSearchPlatform: "ytmsearch",
129
+ * volumeDecrementer: 0.75,
130
+ * //requesterTransformer: YourRequesterTransformerFunction,
131
+ * onDisconnect: {
132
+ * autoReconnect: true,
133
+ * destroyPlayer: false
134
+ * },
135
+ * onEmptyQueue: {
136
+ * destroyAfterMs: 30_000,
137
+ * //autoPlayFunction: YourAutoplayFunction,
138
+ * },
139
+ * useUnresolvedData: true
140
+ * },
141
+ * queueOptions: {
142
+ * maxPreviousTracks: 25,
143
+ * //queueStore: yourCustomQueueStoreManagerClass,
144
+ * //queueChangesWatcher: yourCustomQueueChangesWatcherClass
145
+ * },
146
+ * linksBlacklist: [],
147
+ * linksWhitelist: [],
148
+ * advancedOptions: {
149
+ * debugOptions: {
150
+ * noAudio: false,
151
+ * playerDestroy: {
152
+ * dontThrowError: false,
153
+ * debugLogs: false
154
+ * }
155
+ * }
156
+ * }
157
+ * ]
158
+ * })
159
+ * ```
160
+ */
89
161
  constructor(options) {
90
162
  super();
91
163
  if (!options)
@@ -97,6 +169,47 @@ export class LavalinkManager extends EventEmitter {
97
169
  // create classes
98
170
  this.nodeManager = new NodeManager(this);
99
171
  }
172
+ /**
173
+ * Get a Player from Lava
174
+ * @param guildId The guildId of the player
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * const player = client.lavalink.getPlayer(interaction.guildId);
179
+ * ```
180
+ * A quicker and easier way than doing:
181
+ * ```ts
182
+ * const player = client.lavalink.players.get(interaction.guildId);
183
+ * ```
184
+ * @returns
185
+ */
186
+ getPlayer(guildId) {
187
+ return this.players.get(guildId);
188
+ }
189
+ /**
190
+ * Create a Music-Player. If a player exists, then it returns it before creating a new one
191
+ * @param options
192
+ * @returns
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * const player = client.lavalink.createPlayer({
197
+ * guildId: interaction.guildId,
198
+ * voiceChannelId: interaction.member.voice.channelId,
199
+ * // everything below is optional
200
+ * textChannelId: interaction.channelId,
201
+ * volume: 100,
202
+ * selfDeaf: true,
203
+ * selfMute: false,
204
+ * instaUpdateFiltersFix: true,
205
+ * applyVolumeAsFilter: false
206
+ * //only needed if you want to autopick node by region (configured by you)
207
+ * // vcRegion: interaction.member.voice.rtcRegion,
208
+ * // provide a specific node
209
+ * // node: client.lavalink.nodeManager.leastUsedNodes("memory")[0]
210
+ * });
211
+ * ```
212
+ */
100
213
  createPlayer(options) {
101
214
  const oldPlayer = this.getPlayer(options?.guildId);
102
215
  if (oldPlayer)
@@ -105,15 +218,29 @@ export class LavalinkManager extends EventEmitter {
105
218
  this.players.set(newPlayer.guildId, newPlayer);
106
219
  return newPlayer;
107
220
  }
108
- getPlayer(guildId) {
109
- return this.players.get(guildId);
110
- }
221
+ /**
222
+ * Destroy a player with optional destroy reason and disconnect it from the voice channel
223
+ * @param guildId
224
+ * @param destroyReason
225
+ * @returns
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * client.lavalink.destroyPlayer(interaction.guildId, "forcefully destroyed the player");
230
+ * // recommend to do it on the player tho: player.destroy("forcefully destroyed the player");
231
+ * ```
232
+ */
111
233
  destroyPlayer(guildId, destroyReason) {
112
234
  const oldPlayer = this.getPlayer(guildId);
113
235
  if (!oldPlayer)
114
236
  return;
115
237
  return oldPlayer.destroy(destroyReason);
116
238
  }
239
+ /**
240
+ * Delete's a player from the cache without destroying it on lavalink (only works when it's disconnected)
241
+ * @param guildId
242
+ * @returns
243
+ */
117
244
  deletePlayer(guildId) {
118
245
  const oldPlayer = this.getPlayer(guildId);
119
246
  if (!oldPlayer)
@@ -127,12 +254,27 @@ export class LavalinkManager extends EventEmitter {
127
254
  }
128
255
  return this.players.delete(guildId);
129
256
  }
257
+ /**
258
+ * Checks wether the the lib is useable based on if any node is connected
259
+ */
130
260
  get useable() {
131
261
  return this.nodeManager.nodes.filter(v => v.connected).size > 0;
132
262
  }
133
263
  /**
134
- * Initiates the Manager.
264
+ * Initiates the Manager, creates all nodes and connects all of them
135
265
  * @param clientData
266
+ *
267
+ * @example
268
+ *
269
+ * ```ts
270
+ * // on the bot ready event
271
+ * client.on("ready", () => {
272
+ * client.lavalink.init({
273
+ * id: client.user.id,
274
+ * username: client.user.username
275
+ * });
276
+ * });
277
+ * ```
136
278
  */
137
279
  async init(clientData) {
138
280
  if (this.initiated)
@@ -162,7 +304,18 @@ export class LavalinkManager extends EventEmitter {
162
304
  }
163
305
  /**
164
306
  * Sends voice data to the Lavalink server.
307
+ * ! Without this the library won't work
165
308
  * @param data
309
+ *
310
+ * @example
311
+ *
312
+ * ```ts
313
+ * // on the bot "raw" event
314
+ * client.on("raw", (d) => {
315
+ * // required in order to send audio updates and register channel deletion etc.
316
+ * client.lavalink.sendRawData(d)
317
+ * })
318
+ * ```
166
319
  */
167
320
  async sendRawData(data) {
168
321
  if (!this.initiated) {
@@ -172,7 +172,7 @@ export declare class Player {
172
172
  * @param query Query for your data
173
173
  * @param requestUser
174
174
  */
175
- search(query: SearchQuery, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | import("./Utils").SearchResult>;
175
+ search(query: SearchQuery, requestUser: unknown): Promise<import("./Utils").SearchResult | import("./Utils").UnresolvedSearchResult>;
176
176
  /**
177
177
  * Pause the player
178
178
  */
@@ -239,7 +239,8 @@ export class ManagerUtils {
239
239
  source: DefaultSources[(typeof query === "string" ? undefined : query.source?.trim?.()?.toLowerCase?.()) ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? (typeof query === "string" ? undefined : query.source?.trim?.()?.toLowerCase?.()) ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
240
240
  };
241
241
  const foundSource = Object.keys(DefaultSources).find(source => Query.query?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
242
- if (foundSource && DefaultSources[foundSource]) {
242
+ // ignore links...
243
+ if (foundSource && !["https", "http"].includes(foundSource) && DefaultSources[foundSource]) {
243
244
  Query.source = DefaultSources[foundSource]; // set the source to ytsearch:
244
245
  Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length); // remove ytsearch: from the query
245
246
  }