lavalink-client 2.3.3 → 2.3.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.
package/README.md CHANGED
@@ -189,28 +189,10 @@ client.lavalink = new LavalinkManager({
189
189
 
190
190
  ## How to do resuming
191
191
 
192
- ```js
193
- // 1. while the player is playing, make sure to enable it:
194
- const durationToKeepPlayingInMS = 600_000;
195
- await player.node.updateSession(true, durationToKeepPlayingInMS);
196
- ```
197
-
198
- ```js
199
- // 2. make sure to have an eventlistener for resuming events somewhere
200
- client.lavalink.nodeManager.on("resumed", (node, payload, fetchedPlayers) => {
201
- // create players:
202
- for(const fetchedPlayer of fetchedPlayers) {
203
- const player = client.lavalink.createPlayer({
204
- guildId: fetchedPlayer.guildId,
205
- });
206
- player.setVolume(fetchedPlayer.volume);
207
- // and apply other things (e.g. paused, voice, filters, state, ...) (stuff like vc channel, text channel you need to store somewhere)
208
- await player.queue.utils.sync(); // only works with a queuestore
209
- // you can now overwride the player.queue.current track from the fetchedPlayer, or use the one from the queue.uztils.sync function
210
- // continue with your resuming code...
211
- }
212
- })
213
- ```
192
+ 1. You need to enable resuming on a __connected__ Lavalink node : **` node.updateSession(true, 360e3) `**
193
+ 2. The NodeManager#resumed event will emit when the node resumes, you retrieves all fetchedPlayers (fetched by the client), and thus all you need to do is re-create all player instances (and possibly the queues too)
194
+ - For that is the queuestore useful
195
+ - To save the playerData you can utilize smt like playerUpdate event.
214
196
 
215
197
  ## Resuming full Example
216
198
  Full code sample: can be found on the [Testbot in here](https://github.com/Tomato6966/lavalink-client/blob/main/testBot/Utils/handleResuming.ts)
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { EventEmitter } from "stream";
2
+ import { EventEmitter } from "events";
3
3
  import { LavalinkNode } from "./Node";
4
4
  import { MiniMap } from "./Utils";
5
5
  import type { LavalinkNodeIdentifier, LavalinkNodeOptions, NodeManagerEvents } from "./Types/Node";
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NodeManager = void 0;
4
- const stream_1 = require("stream");
4
+ const events_1 = require("events");
5
5
  const Constants_1 = require("./Constants");
6
6
  const Node_1 = require("./Node");
7
7
  const Utils_1 = require("./Utils");
8
- class NodeManager extends stream_1.EventEmitter {
8
+ class NodeManager extends events_1.EventEmitter {
9
9
  /**
10
10
  * Emit an event
11
11
  * @param event The event to emit
@@ -138,7 +138,7 @@ class Player {
138
138
  */
139
139
  async play(options = {}) {
140
140
  if (this.get("internal_queueempty")) {
141
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
141
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
142
142
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayQueueEmptyTimeoutClear, {
143
143
  state: "log",
144
144
  message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`,
@@ -150,8 +150,31 @@ class Player {
150
150
  }
151
151
  // if clientTrack provided, override options.track object
152
152
  if (options?.clientTrack && (this.LavalinkManager.utils.isTrack(options?.clientTrack) || this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))) {
153
- if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))
154
- await options.clientTrack.resolve(this);
153
+ if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack)) {
154
+ try {
155
+ // resolve the unresolved track
156
+ await options.clientTrack.resolve(this);
157
+ }
158
+ catch (error) {
159
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
160
+ this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayUnresolvedTrackFailed, {
161
+ state: "error",
162
+ error: error,
163
+ message: `Player Play was called with clientTrack, Song is unresolved, but couldn't resolve it`,
164
+ functionLayer: "Player > play() > resolve currentTrack",
165
+ });
166
+ }
167
+ this.LavalinkManager.emit("trackError", this, this.queue.current, error);
168
+ if (options && "clientTrack" in options)
169
+ delete options.clientTrack;
170
+ if (options && "track" in options)
171
+ delete options.track;
172
+ // try to play the next track if possible
173
+ if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
174
+ return this.play(options);
175
+ return this;
176
+ }
177
+ }
155
178
  if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack)
156
179
  options.clientTrack.userData = { ...(options?.clientTrack.userData || {}), ...(options.track?.userData || {}) };
157
180
  options.track = {
@@ -185,7 +208,7 @@ class Player {
185
208
  ...(track.userData || {}),
186
209
  requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {})
187
210
  };
188
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
211
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
189
212
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayWithTrackReplace, {
190
213
  state: "log",
191
214
  message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`,
@@ -209,7 +232,7 @@ class Player {
209
232
  if (!this.queue.current && this.queue.tracks.length)
210
233
  await (0, Utils_1.queueTrackEnd)(this);
211
234
  if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
212
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
235
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
213
236
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayUnresolvedTrack, {
214
237
  state: "log",
215
238
  message: `Player Play was called, current Queue Song is unresolved, resolving the track.`,
@@ -223,7 +246,7 @@ class Player {
223
246
  this.queue.current.userData = { ...(this.queue.current?.userData || {}), ...(options.track?.userData || {}) };
224
247
  }
225
248
  catch (error) {
226
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
249
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
227
250
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayUnresolvedTrackFailed, {
228
251
  state: "error",
229
252
  error: error,
@@ -297,7 +320,7 @@ class Player {
297
320
  : this.volume), 1000), 0));
298
321
  const now = performance.now();
299
322
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
300
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
323
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
301
324
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerVolumeAsFilter, {
302
325
  state: "log",
303
326
  message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`,
@@ -349,7 +372,7 @@ class Player {
349
372
  async search(query, requestUser, throwOnEmpty = false) {
350
373
  const Query = this.LavalinkManager.utils.transformQuery(query);
351
374
  if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) {
352
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
375
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
353
376
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.BandcampSearchLokalEngine, {
354
377
  state: "log",
355
378
  message: `Player.search was called with a Bandcamp Query, but no bandcamp search was enabled on lavalink, searching with the custom Search Engine.`,
@@ -559,7 +582,7 @@ class Player {
559
582
  const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
560
583
  if (!updateNode)
561
584
  throw new Error("Could not find the new Node");
562
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
585
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
563
586
  this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerChangeNode, {
564
587
  state: "log",
565
588
  message: `Player.changeNode() was executed, trying to change from "${this.node.id}" to "${updateNode.id}"`,
@@ -427,11 +427,27 @@ async function queueTrackEnd(player) {
427
427
  player.queue.tracks.push(player.queue.current);
428
428
  // change the current Track to the next upcoming one
429
429
  const nextSong = player.queue.tracks.shift();
430
- if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
431
- await nextSong.resolve(player);
432
- player.queue.current = nextSong || null;
433
- // save it in the DB
434
- await player.queue.utils.save();
430
+ try {
431
+ if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
432
+ await nextSong.resolve(player);
433
+ player.queue.current = nextSong || null;
434
+ // save it in the DB
435
+ await player.queue.utils.save();
436
+ }
437
+ catch (error) {
438
+ if (player.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
439
+ player.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayUnresolvedTrackFailed, {
440
+ state: "error",
441
+ error: error,
442
+ message: `queueTrackEnd Util was called, tried to resolve the next track, but failed to find the closest matching song`,
443
+ functionLayer: "Player > play() > resolve currentTrack",
444
+ });
445
+ }
446
+ player.LavalinkManager.emit("trackError", player, player.queue.current, error);
447
+ // try to play the next track if possible
448
+ if (player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
449
+ return queueTrackEnd(player);
450
+ }
435
451
  // return the new current Track
436
452
  return player.queue.current;
437
453
  }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { EventEmitter } from "stream";
2
+ import { EventEmitter } from "events";
3
3
  import { LavalinkNode } from "./Node";
4
4
  import { MiniMap } from "./Utils";
5
5
  import type { LavalinkNodeIdentifier, LavalinkNodeOptions, NodeManagerEvents } from "./Types/Node";
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from "stream";
1
+ import { EventEmitter } from "events";
2
2
  import { DestroyReasons } from "./Constants";
3
3
  import { LavalinkNode } from "./Node";
4
4
  import { MiniMap } from "./Utils";
@@ -135,7 +135,7 @@ export class Player {
135
135
  */
136
136
  async play(options = {}) {
137
137
  if (this.get("internal_queueempty")) {
138
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
138
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
139
139
  this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayQueueEmptyTimeoutClear, {
140
140
  state: "log",
141
141
  message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`,
@@ -147,8 +147,31 @@ export class Player {
147
147
  }
148
148
  // if clientTrack provided, override options.track object
149
149
  if (options?.clientTrack && (this.LavalinkManager.utils.isTrack(options?.clientTrack) || this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))) {
150
- if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))
151
- await options.clientTrack.resolve(this);
150
+ if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack)) {
151
+ try {
152
+ // resolve the unresolved track
153
+ await options.clientTrack.resolve(this);
154
+ }
155
+ catch (error) {
156
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
157
+ this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
158
+ state: "error",
159
+ error: error,
160
+ message: `Player Play was called with clientTrack, Song is unresolved, but couldn't resolve it`,
161
+ functionLayer: "Player > play() > resolve currentTrack",
162
+ });
163
+ }
164
+ this.LavalinkManager.emit("trackError", this, this.queue.current, error);
165
+ if (options && "clientTrack" in options)
166
+ delete options.clientTrack;
167
+ if (options && "track" in options)
168
+ delete options.track;
169
+ // try to play the next track if possible
170
+ if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
171
+ return this.play(options);
172
+ return this;
173
+ }
174
+ }
152
175
  if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack)
153
176
  options.clientTrack.userData = { ...(options?.clientTrack.userData || {}), ...(options.track?.userData || {}) };
154
177
  options.track = {
@@ -182,7 +205,7 @@ export class Player {
182
205
  ...(track.userData || {}),
183
206
  requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {})
184
207
  };
185
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
208
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
186
209
  this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayWithTrackReplace, {
187
210
  state: "log",
188
211
  message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`,
@@ -206,7 +229,7 @@ export class Player {
206
229
  if (!this.queue.current && this.queue.tracks.length)
207
230
  await queueTrackEnd(this);
208
231
  if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
209
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
232
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
210
233
  this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrack, {
211
234
  state: "log",
212
235
  message: `Player Play was called, current Queue Song is unresolved, resolving the track.`,
@@ -220,7 +243,7 @@ export class Player {
220
243
  this.queue.current.userData = { ...(this.queue.current?.userData || {}), ...(options.track?.userData || {}) };
221
244
  }
222
245
  catch (error) {
223
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
246
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
224
247
  this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
225
248
  state: "error",
226
249
  error: error,
@@ -294,7 +317,7 @@ export class Player {
294
317
  : this.volume), 1000), 0));
295
318
  const now = performance.now();
296
319
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
297
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
320
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
298
321
  this.LavalinkManager.emit("debug", DebugEvents.PlayerVolumeAsFilter, {
299
322
  state: "log",
300
323
  message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`,
@@ -346,7 +369,7 @@ export class Player {
346
369
  async search(query, requestUser, throwOnEmpty = false) {
347
370
  const Query = this.LavalinkManager.utils.transformQuery(query);
348
371
  if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) {
349
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
372
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
350
373
  this.LavalinkManager.emit("debug", DebugEvents.BandcampSearchLokalEngine, {
351
374
  state: "log",
352
375
  message: `Player.search was called with a Bandcamp Query, but no bandcamp search was enabled on lavalink, searching with the custom Search Engine.`,
@@ -556,7 +579,7 @@ export class Player {
556
579
  const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
557
580
  if (!updateNode)
558
581
  throw new Error("Could not find the new Node");
559
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
582
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
560
583
  this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
561
584
  state: "log",
562
585
  message: `Player.changeNode() was executed, trying to change from "${this.node.id}" to "${updateNode.id}"`,
@@ -421,11 +421,27 @@ export async function queueTrackEnd(player) {
421
421
  player.queue.tracks.push(player.queue.current);
422
422
  // change the current Track to the next upcoming one
423
423
  const nextSong = player.queue.tracks.shift();
424
- if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
425
- await nextSong.resolve(player);
426
- player.queue.current = nextSong || null;
427
- // save it in the DB
428
- await player.queue.utils.save();
424
+ try {
425
+ if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
426
+ await nextSong.resolve(player);
427
+ player.queue.current = nextSong || null;
428
+ // save it in the DB
429
+ await player.queue.utils.save();
430
+ }
431
+ catch (error) {
432
+ if (player.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
433
+ player.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
434
+ state: "error",
435
+ error: error,
436
+ message: `queueTrackEnd Util was called, tried to resolve the next track, but failed to find the closest matching song`,
437
+ functionLayer: "Player > play() > resolve currentTrack",
438
+ });
439
+ }
440
+ player.LavalinkManager.emit("trackError", player, player.queue.current, error);
441
+ // try to play the next track if possible
442
+ if (player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
443
+ return queueTrackEnd(player);
444
+ }
429
445
  // return the new current Track
430
446
  return player.queue.current;
431
447
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { EventEmitter } from "stream";
2
+ import { EventEmitter } from "events";
3
3
  import { LavalinkNode } from "./Node";
4
4
  import { MiniMap } from "./Utils";
5
5
  import type { LavalinkNodeIdentifier, LavalinkNodeOptions, NodeManagerEvents } from "./Types/Node";
package/package.json CHANGED
@@ -1,21 +1,27 @@
1
1
  {
2
2
  "name": "lavalink-client",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
7
7
  "types": "dist/types/index.d.js",
8
8
  "scripts": {
9
9
  "build": "npm run build:cjs && npm run build:esm && npm run build:types",
10
- "build:cjs": "node tools/cleanup cjs && tsc -p config/tsconfig.cjs.json",
11
- "build:esm": "node tools/cleanup esm && tsc -p config/tsconfig.esm.json",
12
- "build:types": "node tools/cleanup types && tsc -p config/tsconfig.types.json",
10
+ "build:cjs": "node tools/cleanup cjs && tsc -p config/tsconfig.cjs.json && tsc-alias -p config/tsconfig.cjs.json && node tools/fixup cjs",
11
+ "build:esm": "node tools/cleanup esm && tsc -p config/tsconfig.esm.json && tsc-alias -p config/tsconfig.esm.json && node tools/fixup esm",
12
+ "build:types": "node tools/cleanup types && tsc -p config/tsconfig.types.json && tsc-alias -p config/tsconfig.types.json",
13
13
  "clean": "node tools/cleanup",
14
14
  "lint": "eslint .",
15
15
  "lint:fix": "npm run lint -- --fix",
16
16
  "test": "node -v",
17
17
  "docs": "npx typedoc"
18
18
  },
19
+ "exports": {
20
+ "require": "./dist/cjs/index.js",
21
+ "import": "./dist/esm/index.js",
22
+ "types": "./dist/types/index.d.js",
23
+ "default": "./dist/cjs/index.js"
24
+ },
19
25
  "publishConfig": {
20
26
  "access": "public"
21
27
  },
@@ -52,7 +58,7 @@
52
58
  "@typescript-eslint/eslint-plugin": "^6.4.0",
53
59
  "@typescript-eslint/parser": "^6.4.0",
54
60
  "eslint": "^8.47.0",
55
- "ts-loader": "^9.4.4",
61
+ "tsc-alias": "^1.8.10",
56
62
  "typedoc": "^0.25.4",
57
63
  "typedoc-theme-hierarchy": "^4.1.2",
58
64
  "typescript": "^5.1.6"
@@ -62,6 +68,7 @@
62
68
  "ws": "^8.13.0"
63
69
  },
64
70
  "engines": {
65
- "node": ">=18.0.0"
71
+ "node": ">=18.0.0",
72
+ "bun": ">=1.0.0"
66
73
  }
67
74
  }