lavalink-client 2.3.6 → 2.4.1

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.
Files changed (57) hide show
  1. package/README.md +56 -7
  2. package/dist/cjs/structures/Constants.d.ts +4 -0
  3. package/dist/cjs/structures/Constants.js +7 -2
  4. package/dist/cjs/structures/Filters.d.ts +24 -0
  5. package/dist/cjs/structures/Filters.js +34 -10
  6. package/dist/cjs/structures/LavalinkManager.d.ts +4 -5
  7. package/dist/cjs/structures/LavalinkManager.js +75 -30
  8. package/dist/cjs/structures/Node.d.ts +30 -16
  9. package/dist/cjs/structures/Node.js +165 -84
  10. package/dist/cjs/structures/NodeManager.d.ts +2 -2
  11. package/dist/cjs/structures/NodeManager.js +19 -19
  12. package/dist/cjs/structures/Player.d.ts +10 -3
  13. package/dist/cjs/structures/Player.js +12 -0
  14. package/dist/cjs/structures/Queue.d.ts +9 -10
  15. package/dist/cjs/structures/Queue.js +3 -3
  16. package/dist/cjs/structures/Types/Manager.d.ts +40 -0
  17. package/dist/cjs/structures/Types/Node.d.ts +0 -1
  18. package/dist/cjs/structures/Types/Player.d.ts +5 -1
  19. package/dist/cjs/structures/Types/Queue.d.ts +6 -6
  20. package/dist/cjs/structures/Types/Track.d.ts +3 -1
  21. package/dist/cjs/structures/Types/Utils.d.ts +17 -2
  22. package/dist/cjs/structures/Utils.js +3 -10
  23. package/dist/esm/structures/Constants.d.ts +4 -0
  24. package/dist/esm/structures/Constants.js +6 -1
  25. package/dist/esm/structures/Filters.d.ts +24 -0
  26. package/dist/esm/structures/Filters.js +34 -10
  27. package/dist/esm/structures/LavalinkManager.d.ts +4 -5
  28. package/dist/esm/structures/LavalinkManager.js +75 -30
  29. package/dist/esm/structures/Node.d.ts +30 -16
  30. package/dist/esm/structures/Node.js +165 -84
  31. package/dist/esm/structures/NodeManager.d.ts +2 -2
  32. package/dist/esm/structures/NodeManager.js +20 -20
  33. package/dist/esm/structures/Player.d.ts +10 -3
  34. package/dist/esm/structures/Player.js +12 -0
  35. package/dist/esm/structures/Queue.d.ts +9 -10
  36. package/dist/esm/structures/Queue.js +3 -3
  37. package/dist/esm/structures/Types/Manager.d.ts +40 -0
  38. package/dist/esm/structures/Types/Node.d.ts +0 -1
  39. package/dist/esm/structures/Types/Player.d.ts +5 -1
  40. package/dist/esm/structures/Types/Queue.d.ts +6 -6
  41. package/dist/esm/structures/Types/Track.d.ts +3 -1
  42. package/dist/esm/structures/Types/Utils.d.ts +17 -2
  43. package/dist/esm/structures/Utils.js +0 -7
  44. package/dist/types/structures/Constants.d.ts +4 -0
  45. package/dist/types/structures/Filters.d.ts +24 -0
  46. package/dist/types/structures/LavalinkManager.d.ts +4 -5
  47. package/dist/types/structures/Node.d.ts +30 -16
  48. package/dist/types/structures/NodeManager.d.ts +2 -2
  49. package/dist/types/structures/Player.d.ts +10 -3
  50. package/dist/types/structures/Queue.d.ts +9 -10
  51. package/dist/types/structures/Types/Manager.d.ts +40 -0
  52. package/dist/types/structures/Types/Node.d.ts +0 -1
  53. package/dist/types/structures/Types/Player.d.ts +5 -1
  54. package/dist/types/structures/Types/Queue.d.ts +6 -6
  55. package/dist/types/structures/Types/Track.d.ts +3 -1
  56. package/dist/types/structures/Types/Utils.d.ts +17 -2
  57. package/package.json +23 -18
@@ -17,6 +17,7 @@ class LavalinkNode {
17
17
  }
18
18
  heartBeatInterval;
19
19
  pingTimeout;
20
+ isAlive = false;
20
21
  /** The provided Options of the Node */
21
22
  options;
22
23
  /** The amount of rest calls the node has made. */
@@ -78,7 +79,7 @@ class LavalinkNode {
78
79
  retryAmount: 5,
79
80
  retryDelay: 10e3,
80
81
  requestSignalTimeoutMS: 10000,
81
- heartBeatInterval: 30000,
82
+ heartBeatInterval: 30_000,
82
83
  closeOnError: true,
83
84
  enablePingOnStatsCheck: true,
84
85
  ...options
@@ -141,32 +142,22 @@ class LavalinkNode {
141
142
  const url = new URL(`${this.restAddress}${options.path}`);
142
143
  url.searchParams.append("trace", "true");
143
144
  const urlToUse = this.getRequestingUrl(url, options?.extraQueryUrlParams);
145
+ const originalOptions = structuredClone(options);
144
146
  delete options.path;
145
147
  delete options.extraQueryUrlParams;
146
- const request = await fetch(urlToUse, options);
148
+ const response = await fetch(urlToUse, options);
147
149
  this.calls++;
148
- return { request, options };
150
+ return { response, options: originalOptions };
149
151
  }
150
- /**
151
- * Makes an API call to the Node. Should only be used for manual parsing like for not supported plugins
152
- * @param endpoint The endpoint that we will make the call to
153
- * @param modify Used to modify the request before being sent
154
- * @returns The returned data
155
- *
156
- * @example
157
- * ```ts
158
- * player.node.request(`/loadtracks?identifier=Never gonna give you up`, (options) => options.method = "GET", false);
159
- * ```
160
- */
161
- async request(endpoint, modify, parseAsText = false) {
152
+ async request(endpoint, modify, parseAsText) {
162
153
  if (!this.connected)
163
154
  throw new Error("The node is not connected to the Lavalink Server!, Please call node.connect() first!");
164
- const { request, options } = await this.rawRequest(endpoint, modify);
155
+ const { response, options } = await this.rawRequest(endpoint, modify);
165
156
  if (["DELETE", "PUT"].includes(options.method))
166
157
  return;
167
- if (request.status === 404)
168
- throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${JSON.stringify(request.headers)}`);
169
- return parseAsText ? await request.text() : await request.json();
158
+ if (response.status === 404)
159
+ throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${JSON.stringify(response.headers)}`);
160
+ return parseAsText ? await response.text() : await response.json();
170
161
  }
171
162
  /**
172
163
  * Search something raw on the node, please note only add tracks to players of that node
@@ -241,7 +232,7 @@ class LavalinkNode {
241
232
  * @param query LavaSearchQuery Object
242
233
  * @param requestUser Request User for creating the player(s)
243
234
  * @param throwOnEmpty Wether to throw on an empty result or not
244
- * @returns LavaSearchresult
235
+ * @returns LavaSearchresult (SearchResult if link is provided)
245
236
  *
246
237
  * @example
247
238
  * ```ts
@@ -261,8 +252,8 @@ class LavalinkNode {
261
252
  throw new RangeError(`there is no lavasearch-plugin available in the lavalink node: ${this.id}`);
262
253
  if (!this.info.plugins.find(v => v.name === "lavasrc-plugin"))
263
254
  throw new RangeError(`there is no lavasrc-plugin available in the lavalink node: ${this.id}`);
264
- const { request } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
265
- const res = (request.status === 204 ? {} : await request.json());
255
+ const { response } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
256
+ const res = (response.status === 204 ? {} : await response.json());
266
257
  if (throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length) {
267
258
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
268
259
  this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.LavaSearchNothingFound, {
@@ -299,7 +290,6 @@ class LavalinkNode {
299
290
  this.syncPlayerData(data);
300
291
  const res = await this.request(`/sessions/${this.sessionId}/players/${data.guildId}`, r => {
301
292
  r.method = "PATCH";
302
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
303
293
  r.headers["Content-Type"] = "application/json";
304
294
  r.body = JSON.stringify(data.playerOptions);
305
295
  if (data.noReplace) {
@@ -315,7 +305,8 @@ class LavalinkNode {
315
305
  functionLayer: "LavalinkNode > node > updatePlayer()",
316
306
  });
317
307
  }
318
- return this.syncPlayerData({}, res), res;
308
+ this.syncPlayerData({}, res);
309
+ return res;
319
310
  }
320
311
  /**
321
312
  * Destroys the Player on the Lavalink Server
@@ -384,6 +375,7 @@ class LavalinkNode {
384
375
  if (this.pingTimeout)
385
376
  clearTimeout(this.pingTimeout);
386
377
  this.pingTimeout = setTimeout(() => {
378
+ this.pingTimeout = null;
387
379
  if (!this.socket) {
388
380
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
389
381
  this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.NoSocketOnDestroy, {
@@ -403,7 +395,7 @@ class LavalinkNode {
403
395
  }
404
396
  this.isAlive = false;
405
397
  this.socket.terminate();
406
- }, 65000); // the stats endpoint get's sent every 60s. se wee add a 5s buffer to make sure we don't miss any stats message
398
+ }, 65_000); // the stats endpoint get's sent every 60s. se wee add a 5s buffer to make sure we don't miss any stats message
407
399
  }
408
400
  /**
409
401
  * Get the id of the node
@@ -419,7 +411,7 @@ class LavalinkNode {
419
411
  }
420
412
  /**
421
413
  * Destroys the Node-Connection (Websocket) and all player's of the node
422
- * @param destroyReason Destroyreason to use when destroying the players
414
+ * @param destroyReason Destroy Reason to use when destroying the players
423
415
  * @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
424
416
  * @returns void
425
417
  *
@@ -450,6 +442,28 @@ class LavalinkNode {
450
442
  }
451
443
  return;
452
444
  }
445
+ /**
446
+ * Disconnects the Node-Connection (Websocket)
447
+ * @param disconnectReason Disconnect Reason to use when disconnecting Node
448
+ * @returns void
449
+ *
450
+ * Also the node will not get re-connected again.
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * player.node.destroy("custom Player Destroy Reason", true);
455
+ * ```
456
+ */
457
+ disconnect(disconnectReason) {
458
+ if (!this.connected)
459
+ return;
460
+ this.socket.close(1000, "Node-Disconnect");
461
+ this.socket.removeAllListeners();
462
+ this.socket = null;
463
+ this.reconnectAttempts = 1;
464
+ clearTimeout(this.reconnectTimeout);
465
+ this.NodeManager.emit("disconnect", this, { code: 1000, reason: disconnectReason });
466
+ }
453
467
  /**
454
468
  * Returns if connected to the Node.
455
469
  *
@@ -460,11 +474,8 @@ class LavalinkNode {
460
474
  * ```
461
475
  */
462
476
  get connected() {
463
- if (!this.socket)
464
- return false;
465
- return this.socket.readyState === ws_1.default.OPEN;
477
+ return this.socket && this.socket.readyState === ws_1.default.OPEN;
466
478
  }
467
- isAlive = false;
468
479
  /**
469
480
  * Returns the current ConnectionStatus
470
481
  *
@@ -585,7 +596,6 @@ class LavalinkNode {
585
596
  return await this.request(`/decodetracks`, r => {
586
597
  r.method = "POST";
587
598
  r.body = JSON.stringify(encodeds);
588
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
589
599
  r.headers["Content-Type"] = "application/json";
590
600
  }).then((r) => r.map(track => this.NodeManager.LavalinkManager.utils.buildTrack(track, requester)));
591
601
  }
@@ -661,7 +671,7 @@ class LavalinkNode {
661
671
  throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
662
672
  return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`, (options) => {
663
673
  options.method = "POST";
664
- }).catch(() => { });
674
+ });
665
675
  },
666
676
  /**
667
677
  * unsubscribe from lyrics updates for a guild
@@ -685,7 +695,7 @@ class LavalinkNode {
685
695
  throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
686
696
  return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/unsubscribe`, (options) => {
687
697
  options.method = "DELETE";
688
- }).catch(() => { });
698
+ });
689
699
  },
690
700
  };
691
701
  /**
@@ -760,9 +770,8 @@ class LavalinkNode {
760
770
  unmarkFailedAddress: async (address) => {
761
771
  if (!this.sessionId)
762
772
  throw new Error("the Lavalink-Node is either not ready, or not up to date!");
763
- await this.request(`/routeplanner/free/address`, r => {
773
+ return await this.request(`/routeplanner/free/address`, r => {
764
774
  r.method = "POST";
765
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
766
775
  r.headers["Content-Type"] = "application/json";
767
776
  r.body = JSON.stringify({ address });
768
777
  });
@@ -781,7 +790,6 @@ class LavalinkNode {
781
790
  throw new Error("the Lavalink-Node is either not ready, or not up to date!");
782
791
  return await this.request(`/routeplanner/free/all`, r => {
783
792
  r.method = "POST";
784
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
785
793
  r.headers["Content-Type"] = "application/json";
786
794
  });
787
795
  }
@@ -794,6 +802,7 @@ class LavalinkNode {
794
802
  throw new SyntaxError("LavalinkNode requires 'host'");
795
803
  if (!this.options.port)
796
804
  throw new SyntaxError("LavalinkNode requires 'port'");
805
+ // TODO add more validations
797
806
  }
798
807
  /**
799
808
  * Sync the data of the player you make an action to lavalink to
@@ -858,11 +867,13 @@ class LavalinkNode {
858
867
  const player = this.NodeManager.LavalinkManager.getPlayer(data.guildId);
859
868
  if (!player)
860
869
  return;
861
- if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false)
862
- return player.destroy(Constants_1.DestroyReasons.LavalinkNoVoice);
870
+ if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false) {
871
+ player.destroy(Constants_1.DestroyReasons.LavalinkNoVoice);
872
+ return;
873
+ }
863
874
  player.ping.ws = res?.voice?.ping || player?.ping.ws;
864
875
  }
865
- return true;
876
+ return;
866
877
  }
867
878
  /**
868
879
  * Get the rest Adress for making requests
@@ -896,6 +907,7 @@ class LavalinkNode {
896
907
  return;
897
908
  }
898
909
  this.reconnectTimeout = setTimeout(() => {
910
+ this.reconnectTimeout = null;
899
911
  if (this.reconnectAttempts >= this.options.retryAmount) {
900
912
  const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
901
913
  this.NodeManager.emit("error", this, error);
@@ -931,7 +943,7 @@ class LavalinkNode {
931
943
  this.isAlive = false;
932
944
  this.heartBeatPingTimestamp = performance.now();
933
945
  this.socket.ping();
934
- }, this.options.heartBeatInterval || 30000);
946
+ }, this.options.heartBeatInterval || 30_000);
935
947
  }
936
948
  if (this.reconnectTimeout)
937
949
  clearTimeout(this.reconnectTimeout);
@@ -952,6 +964,8 @@ class LavalinkNode {
952
964
  clearInterval(this.heartBeatInterval);
953
965
  if (code === 1006 && !reason)
954
966
  reason = "Socket got terminated due to no ping connection";
967
+ if (code === 1000 && reason === "Node-Disconnect")
968
+ return; // manually disconnected and already emitted the event.
955
969
  this.NodeManager.emit("disconnect", this, { code, reason });
956
970
  if (code !== 1000 || reason !== "Node-Destroy")
957
971
  this.reconnect();
@@ -976,7 +990,14 @@ class LavalinkNode {
976
990
  d = Buffer.concat(d);
977
991
  else if (d instanceof ArrayBuffer)
978
992
  d = Buffer.from(d);
979
- const payload = JSON.parse(d.toString());
993
+ let payload;
994
+ try {
995
+ payload = JSON.parse(d.toString());
996
+ }
997
+ catch (e) {
998
+ this.NodeManager.emit("error", this, e);
999
+ return;
1000
+ }
980
1001
  if (!payload.op)
981
1002
  return;
982
1003
  this.NodeManager.emit("raw", this, payload);
@@ -1007,7 +1028,7 @@ class LavalinkNode {
1007
1028
  player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
1008
1029
  if (!player.createdTimeStamp && payload.state.time)
1009
1030
  player.createdTimeStamp = payload.state.time;
1010
- if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600000) || (0, path_1.isAbsolute)(player.queue.current?.info?.uri))) {
1031
+ if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600_000) || (0, path_1.isAbsolute)(player.queue.current?.info?.uri))) {
1011
1032
  player.filterManager.filterUpdatedState = false;
1012
1033
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1013
1034
  this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerUpdateFilterFixApply, {
@@ -1099,7 +1120,7 @@ class LavalinkNode {
1099
1120
  }
1100
1121
  return;
1101
1122
  }
1102
- async getTrackOfPayload(payload) {
1123
+ getTrackOfPayload(payload) {
1103
1124
  return "track" in payload
1104
1125
  ? this.NodeManager.LavalinkManager.utils.buildTrack(payload.track, undefined)
1105
1126
  : null;
@@ -1120,7 +1141,7 @@ class LavalinkNode {
1120
1141
  return;
1121
1142
  }
1122
1143
  if (!player.queue.current) {
1123
- player.queue.current = await this.getTrackOfPayload(payload);
1144
+ player.queue.current = this.getTrackOfPayload(payload);
1124
1145
  if (player.queue.current) {
1125
1146
  await player.queue.utils.save();
1126
1147
  }
@@ -1134,11 +1155,12 @@ class LavalinkNode {
1134
1155
  }
1135
1156
  }
1136
1157
  }
1137
- return this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
1158
+ this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
1159
+ return;
1138
1160
  }
1139
1161
  /** @private util function for handling trackEnd event */
1140
1162
  async trackEnd(player, track, payload) {
1141
- const trackToUse = track || await this.getTrackOfPayload(payload);
1163
+ const trackToUse = track || this.getTrackOfPayload(payload);
1142
1164
  // If a track was forcibly played
1143
1165
  if (payload.reason === "replaced") {
1144
1166
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
@@ -1148,7 +1170,8 @@ class LavalinkNode {
1148
1170
  functionLayer: "LavalinkNode > trackEnd()",
1149
1171
  });
1150
1172
  }
1151
- return this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1173
+ this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1174
+ return;
1152
1175
  }
1153
1176
  // If there are no songs in the queue
1154
1177
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
@@ -1162,7 +1185,10 @@ class LavalinkNode {
1162
1185
  // fire event
1163
1186
  this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1164
1187
  // play track if autoSkip is true
1165
- return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
1188
+ if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1189
+ player.play({ noReplace: true });
1190
+ }
1191
+ return;
1166
1192
  }
1167
1193
  // remove tracks from the queue
1168
1194
  if (player.repeatMode !== "track" || player.get("internal_skipped"))
@@ -1180,7 +1206,10 @@ class LavalinkNode {
1180
1206
  // fire event
1181
1207
  this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1182
1208
  // play track if autoSkip is true
1183
- return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
1209
+ if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1210
+ player.play({ noReplace: true });
1211
+ }
1212
+ return;
1184
1213
  }
1185
1214
  /** @private util function for handling trackStuck event */
1186
1215
  async trackStuck(player, track, payload) {
@@ -1196,21 +1225,25 @@ class LavalinkNode {
1196
1225
  functionLayer: "LavalinkNode > trackStuck()",
1197
1226
  });
1198
1227
  }
1199
- return player.destroy(Constants_1.DestroyReasons.TrackStuckMaxTracksErroredPerTime);
1228
+ player.destroy(Constants_1.DestroyReasons.TrackStuckMaxTracksErroredPerTime);
1229
+ return;
1200
1230
  }
1201
1231
  }
1202
- this.NodeManager.LavalinkManager.emit("trackStuck", player, track || await this.getTrackOfPayload(payload), payload);
1232
+ this.NodeManager.LavalinkManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
1203
1233
  // If there are no songs in the queue
1204
1234
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
1205
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1235
+ return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1206
1236
  // remove the current track, and enqueue the next one
1207
1237
  await (0, Utils_1.queueTrackEnd)(player);
1208
1238
  // if no track available, end queue
1209
1239
  if (!player.queue.current) {
1210
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1240
+ return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1211
1241
  }
1212
1242
  // play track if autoSkip is true
1213
- return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
1243
+ if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1244
+ player.play({ noReplace: true });
1245
+ }
1246
+ return;
1214
1247
  }
1215
1248
  /** @private util function for handling trackError event */
1216
1249
  async trackError(player, track, payload) {
@@ -1226,46 +1259,37 @@ class LavalinkNode {
1226
1259
  functionLayer: "LavalinkNode > trackError()",
1227
1260
  });
1228
1261
  }
1229
- return player.destroy(Constants_1.DestroyReasons.TrackErrorMaxTracksErroredPerTime);
1262
+ player.destroy(Constants_1.DestroyReasons.TrackErrorMaxTracksErroredPerTime);
1263
+ return;
1230
1264
  }
1231
1265
  }
1232
- this.NodeManager.LavalinkManager.emit("trackError", player, track || await this.getTrackOfPayload(payload), payload);
1233
- return; // get's handled by trackEnd
1234
- // If there are no songs in the queue
1235
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
1236
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1237
- // remove the current track, and enqueue the next one
1238
- await (0, Utils_1.queueTrackEnd)(player);
1239
- // if no track available, end queue
1240
- if (!player.queue.current)
1241
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1242
- // play track if autoSkip is true
1243
- return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
1266
+ this.NodeManager.LavalinkManager.emit("trackError", player, track || this.getTrackOfPayload(payload), payload);
1267
+ return;
1244
1268
  }
1245
1269
  /** @private util function for handling socketClosed event */
1246
1270
  socketClosed(player, payload) {
1247
1271
  this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
1248
- // i don't think this is needed.
1249
- // this.socket = null;
1250
- // // causing a socket reconnect
1251
- // this.connect();
1252
1272
  return;
1253
1273
  }
1254
1274
  /** @private util function for handling SponsorBlock Segmentloaded event */
1255
1275
  async SponsorBlockSegmentLoaded(player, track, payload) {
1256
- return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || await this.getTrackOfPayload(payload), payload);
1276
+ this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || this.getTrackOfPayload(payload), payload);
1277
+ return;
1257
1278
  }
1258
1279
  /** @private util function for handling SponsorBlock SegmentSkipped event */
1259
1280
  async SponsorBlockSegmentSkipped(player, track, payload) {
1260
- return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || await this.getTrackOfPayload(payload), payload);
1281
+ this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || this.getTrackOfPayload(payload), payload);
1282
+ return;
1261
1283
  }
1262
1284
  /** @private util function for handling SponsorBlock Chaptersloaded event */
1263
1285
  async SponsorBlockChaptersLoaded(player, track, payload) {
1264
- return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || await this.getTrackOfPayload(payload), payload);
1286
+ this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || this.getTrackOfPayload(payload), payload);
1287
+ return;
1265
1288
  }
1266
1289
  /** @private util function for handling SponsorBlock Chaptersstarted event */
1267
1290
  async SponsorBlockChapterStarted(player, track, payload) {
1268
- return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || await this.getTrackOfPayload(payload), payload);
1291
+ this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || this.getTrackOfPayload(payload), payload);
1292
+ return;
1269
1293
  }
1270
1294
  /**
1271
1295
  * Get the current sponsorblocks for the sponsorblock plugin
@@ -1412,8 +1436,10 @@ class LavalinkNode {
1412
1436
  await player.queue.utils.save();
1413
1437
  }
1414
1438
  if (typeof this.NodeManager.LavalinkManager.options.playerOptions?.onEmptyQueue?.destroyAfterMs === "number" && !isNaN(this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs) && this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs >= 0) {
1415
- if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0)
1416
- return player.destroy(Constants_1.DestroyReasons.QueueEmpty);
1439
+ if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) {
1440
+ player.destroy(Constants_1.DestroyReasons.QueueEmpty);
1441
+ return;
1442
+ }
1417
1443
  else {
1418
1444
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1419
1445
  this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TriggerQueueEmptyInterval, {
@@ -1422,16 +1448,23 @@ class LavalinkNode {
1422
1448
  functionLayer: "LavalinkNode > queueEnd() > destroyAfterMs",
1423
1449
  });
1424
1450
  }
1451
+ this.NodeManager.LavalinkManager.emit("playerQueueEmptyStart", player, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs);
1425
1452
  if (player.get("internal_queueempty")) {
1426
1453
  clearTimeout(player.get("internal_queueempty"));
1427
1454
  player.set("internal_queueempty", undefined);
1428
1455
  }
1429
1456
  player.set("internal_queueempty", setTimeout(() => {
1457
+ player.set("internal_queueempty", undefined);
1458
+ if (player.queue.current) {
1459
+ return this.NodeManager.LavalinkManager.emit("playerQueueEmptyCancel", player);
1460
+ }
1461
+ this.NodeManager.LavalinkManager.emit("playerQueueEmptyEnd", player);
1430
1462
  player.destroy(Constants_1.DestroyReasons.QueueEmpty);
1431
1463
  }, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
1432
1464
  }
1433
1465
  }
1434
- return this.NodeManager.LavalinkManager.emit("queueEnd", player, track, payload);
1466
+ this.NodeManager.LavalinkManager.emit("queueEnd", player, track, payload);
1467
+ return;
1435
1468
  }
1436
1469
  /**
1437
1470
  * Emitted whenever a line of lyrics gets emitted
@@ -1440,8 +1473,24 @@ class LavalinkNode {
1440
1473
  * @param {Track} track The track that emitted the event
1441
1474
  * @param {LyricsLineEvent} payload The payload of the event
1442
1475
  */
1443
- LyricsLine(player, track, payload) {
1444
- return this.NodeManager.LavalinkManager.emit("LyricsLine", player, track, payload);
1476
+ async LyricsLine(player, track, payload) {
1477
+ if (!player.queue.current) {
1478
+ player.queue.current = this.getTrackOfPayload(payload);
1479
+ if (player.queue.current) {
1480
+ await player.queue.utils.save();
1481
+ }
1482
+ else {
1483
+ if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1484
+ this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackStartNoTrack, {
1485
+ state: "warn",
1486
+ message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
1487
+ functionLayer: "LavalinkNode > trackStart()",
1488
+ });
1489
+ }
1490
+ }
1491
+ }
1492
+ this.NodeManager.LavalinkManager.emit("LyricsLine", player, track, payload);
1493
+ return;
1445
1494
  }
1446
1495
  /**
1447
1496
  * Emitted whenever the lyrics for a track got found
@@ -1450,8 +1499,24 @@ class LavalinkNode {
1450
1499
  * @param {Track} track The track that emitted the event
1451
1500
  * @param {LyricsFoundEvent} payload The payload of the event
1452
1501
  */
1453
- LyricsFound(player, track, payload) {
1454
- return this.NodeManager.LavalinkManager.emit("LyricsFound", player, track, payload);
1502
+ async LyricsFound(player, track, payload) {
1503
+ if (!player.queue.current) {
1504
+ player.queue.current = this.getTrackOfPayload(payload);
1505
+ if (player.queue.current) {
1506
+ await player.queue.utils.save();
1507
+ }
1508
+ else {
1509
+ if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1510
+ this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackStartNoTrack, {
1511
+ state: "warn",
1512
+ message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
1513
+ functionLayer: "LavalinkNode > trackStart()",
1514
+ });
1515
+ }
1516
+ }
1517
+ }
1518
+ this.NodeManager.LavalinkManager.emit("LyricsFound", player, track, payload);
1519
+ return;
1455
1520
  }
1456
1521
  /**
1457
1522
  * Emitted whenever the lyrics for a track got not found
@@ -1460,8 +1525,24 @@ class LavalinkNode {
1460
1525
  * @param {Track} track The track that emitted the event
1461
1526
  * @param {LyricsNotFoundEvent} payload The payload of the event
1462
1527
  */
1463
- LyricsNotFound(player, track, payload) {
1464
- return this.NodeManager.LavalinkManager.emit("LyricsNotFound", player, track, payload);
1528
+ async LyricsNotFound(player, track, payload) {
1529
+ if (!player.queue.current) {
1530
+ player.queue.current = this.getTrackOfPayload(payload);
1531
+ if (player.queue.current) {
1532
+ await player.queue.utils.save();
1533
+ }
1534
+ else {
1535
+ if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1536
+ this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackStartNoTrack, {
1537
+ state: "warn",
1538
+ message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
1539
+ functionLayer: "LavalinkNode > trackStart()",
1540
+ });
1541
+ }
1542
+ }
1543
+ }
1544
+ this.NodeManager.LavalinkManager.emit("LyricsNotFound", player, track, payload);
1545
+ return;
1465
1546
  }
1466
1547
  }
1467
1548
  exports.LavalinkNode = LavalinkNode;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { EventEmitter } from "events";
3
2
  import { LavalinkNode } from "./Node.js";
4
3
  import { MiniMap } from "./Utils.js";
@@ -55,9 +54,10 @@ export declare class NodeManager extends EventEmitter {
55
54
  /**
56
55
  * Disconnects all Nodes from lavalink ws sockets
57
56
  * @param deleteAllNodes if the nodes should also be deleted from nodeManager.nodes
57
+ * @param destroyPlayers if the players should be destroyed
58
58
  * @returns amount of disconnected Nodes
59
59
  */
60
- disconnectAll(deleteAllNodes?: boolean): Promise<number>;
60
+ disconnectAll(deleteAllNodes?: boolean, destroyPlayers?: boolean): Promise<number>;
61
61
  /**
62
62
  * Connects all not connected nodes
63
63
  * @returns Amount of connected Nodes