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
@@ -13,6 +13,7 @@ export class LavalinkNode {
13
13
  }
14
14
  heartBeatInterval;
15
15
  pingTimeout;
16
+ isAlive = false;
16
17
  /** The provided Options of the Node */
17
18
  options;
18
19
  /** The amount of rest calls the node has made. */
@@ -74,7 +75,7 @@ export class LavalinkNode {
74
75
  retryAmount: 5,
75
76
  retryDelay: 10e3,
76
77
  requestSignalTimeoutMS: 10000,
77
- heartBeatInterval: 30000,
78
+ heartBeatInterval: 30_000,
78
79
  closeOnError: true,
79
80
  enablePingOnStatsCheck: true,
80
81
  ...options
@@ -137,32 +138,22 @@ export class LavalinkNode {
137
138
  const url = new URL(`${this.restAddress}${options.path}`);
138
139
  url.searchParams.append("trace", "true");
139
140
  const urlToUse = this.getRequestingUrl(url, options?.extraQueryUrlParams);
141
+ const originalOptions = structuredClone(options);
140
142
  delete options.path;
141
143
  delete options.extraQueryUrlParams;
142
- const request = await fetch(urlToUse, options);
144
+ const response = await fetch(urlToUse, options);
143
145
  this.calls++;
144
- return { request, options };
146
+ return { response, options: originalOptions };
145
147
  }
146
- /**
147
- * Makes an API call to the Node. Should only be used for manual parsing like for not supported plugins
148
- * @param endpoint The endpoint that we will make the call to
149
- * @param modify Used to modify the request before being sent
150
- * @returns The returned data
151
- *
152
- * @example
153
- * ```ts
154
- * player.node.request(`/loadtracks?identifier=Never gonna give you up`, (options) => options.method = "GET", false);
155
- * ```
156
- */
157
- async request(endpoint, modify, parseAsText = false) {
148
+ async request(endpoint, modify, parseAsText) {
158
149
  if (!this.connected)
159
150
  throw new Error("The node is not connected to the Lavalink Server!, Please call node.connect() first!");
160
- const { request, options } = await this.rawRequest(endpoint, modify);
151
+ const { response, options } = await this.rawRequest(endpoint, modify);
161
152
  if (["DELETE", "PUT"].includes(options.method))
162
153
  return;
163
- if (request.status === 404)
164
- throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${JSON.stringify(request.headers)}`);
165
- return parseAsText ? await request.text() : await request.json();
154
+ if (response.status === 404)
155
+ throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${JSON.stringify(response.headers)}`);
156
+ return parseAsText ? await response.text() : await response.json();
166
157
  }
167
158
  /**
168
159
  * Search something raw on the node, please note only add tracks to players of that node
@@ -237,7 +228,7 @@ export class LavalinkNode {
237
228
  * @param query LavaSearchQuery Object
238
229
  * @param requestUser Request User for creating the player(s)
239
230
  * @param throwOnEmpty Wether to throw on an empty result or not
240
- * @returns LavaSearchresult
231
+ * @returns LavaSearchresult (SearchResult if link is provided)
241
232
  *
242
233
  * @example
243
234
  * ```ts
@@ -257,8 +248,8 @@ export class LavalinkNode {
257
248
  throw new RangeError(`there is no lavasearch-plugin available in the lavalink node: ${this.id}`);
258
249
  if (!this.info.plugins.find(v => v.name === "lavasrc-plugin"))
259
250
  throw new RangeError(`there is no lavasrc-plugin available in the lavalink node: ${this.id}`);
260
- const { request } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
261
- const res = (request.status === 204 ? {} : await request.json());
251
+ const { response } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
252
+ const res = (response.status === 204 ? {} : await response.json());
262
253
  if (throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length) {
263
254
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
264
255
  this.NodeManager.LavalinkManager.emit("debug", DebugEvents.LavaSearchNothingFound, {
@@ -295,7 +286,6 @@ export class LavalinkNode {
295
286
  this.syncPlayerData(data);
296
287
  const res = await this.request(`/sessions/${this.sessionId}/players/${data.guildId}`, r => {
297
288
  r.method = "PATCH";
298
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
299
289
  r.headers["Content-Type"] = "application/json";
300
290
  r.body = JSON.stringify(data.playerOptions);
301
291
  if (data.noReplace) {
@@ -311,7 +301,8 @@ export class LavalinkNode {
311
301
  functionLayer: "LavalinkNode > node > updatePlayer()",
312
302
  });
313
303
  }
314
- return this.syncPlayerData({}, res), res;
304
+ this.syncPlayerData({}, res);
305
+ return res;
315
306
  }
316
307
  /**
317
308
  * Destroys the Player on the Lavalink Server
@@ -380,6 +371,7 @@ export class LavalinkNode {
380
371
  if (this.pingTimeout)
381
372
  clearTimeout(this.pingTimeout);
382
373
  this.pingTimeout = setTimeout(() => {
374
+ this.pingTimeout = null;
383
375
  if (!this.socket) {
384
376
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
385
377
  this.NodeManager.LavalinkManager.emit("debug", DebugEvents.NoSocketOnDestroy, {
@@ -399,7 +391,7 @@ export class LavalinkNode {
399
391
  }
400
392
  this.isAlive = false;
401
393
  this.socket.terminate();
402
- }, 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
394
+ }, 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
403
395
  }
404
396
  /**
405
397
  * Get the id of the node
@@ -415,7 +407,7 @@ export class LavalinkNode {
415
407
  }
416
408
  /**
417
409
  * Destroys the Node-Connection (Websocket) and all player's of the node
418
- * @param destroyReason Destroyreason to use when destroying the players
410
+ * @param destroyReason Destroy Reason to use when destroying the players
419
411
  * @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
420
412
  * @returns void
421
413
  *
@@ -446,6 +438,28 @@ export class LavalinkNode {
446
438
  }
447
439
  return;
448
440
  }
441
+ /**
442
+ * Disconnects the Node-Connection (Websocket)
443
+ * @param disconnectReason Disconnect Reason to use when disconnecting Node
444
+ * @returns void
445
+ *
446
+ * Also the node will not get re-connected again.
447
+ *
448
+ * @example
449
+ * ```ts
450
+ * player.node.destroy("custom Player Destroy Reason", true);
451
+ * ```
452
+ */
453
+ disconnect(disconnectReason) {
454
+ if (!this.connected)
455
+ return;
456
+ this.socket.close(1000, "Node-Disconnect");
457
+ this.socket.removeAllListeners();
458
+ this.socket = null;
459
+ this.reconnectAttempts = 1;
460
+ clearTimeout(this.reconnectTimeout);
461
+ this.NodeManager.emit("disconnect", this, { code: 1000, reason: disconnectReason });
462
+ }
449
463
  /**
450
464
  * Returns if connected to the Node.
451
465
  *
@@ -456,11 +470,8 @@ export class LavalinkNode {
456
470
  * ```
457
471
  */
458
472
  get connected() {
459
- if (!this.socket)
460
- return false;
461
- return this.socket.readyState === WebSocket.OPEN;
473
+ return this.socket && this.socket.readyState === WebSocket.OPEN;
462
474
  }
463
- isAlive = false;
464
475
  /**
465
476
  * Returns the current ConnectionStatus
466
477
  *
@@ -581,7 +592,6 @@ export class LavalinkNode {
581
592
  return await this.request(`/decodetracks`, r => {
582
593
  r.method = "POST";
583
594
  r.body = JSON.stringify(encodeds);
584
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
585
595
  r.headers["Content-Type"] = "application/json";
586
596
  }).then((r) => r.map(track => this.NodeManager.LavalinkManager.utils.buildTrack(track, requester)));
587
597
  }
@@ -657,7 +667,7 @@ export class LavalinkNode {
657
667
  throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
658
668
  return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`, (options) => {
659
669
  options.method = "POST";
660
- }).catch(() => { });
670
+ });
661
671
  },
662
672
  /**
663
673
  * unsubscribe from lyrics updates for a guild
@@ -681,7 +691,7 @@ export class LavalinkNode {
681
691
  throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
682
692
  return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/unsubscribe`, (options) => {
683
693
  options.method = "DELETE";
684
- }).catch(() => { });
694
+ });
685
695
  },
686
696
  };
687
697
  /**
@@ -756,9 +766,8 @@ export class LavalinkNode {
756
766
  unmarkFailedAddress: async (address) => {
757
767
  if (!this.sessionId)
758
768
  throw new Error("the Lavalink-Node is either not ready, or not up to date!");
759
- await this.request(`/routeplanner/free/address`, r => {
769
+ return await this.request(`/routeplanner/free/address`, r => {
760
770
  r.method = "POST";
761
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
762
771
  r.headers["Content-Type"] = "application/json";
763
772
  r.body = JSON.stringify({ address });
764
773
  });
@@ -777,7 +786,6 @@ export class LavalinkNode {
777
786
  throw new Error("the Lavalink-Node is either not ready, or not up to date!");
778
787
  return await this.request(`/routeplanner/free/all`, r => {
779
788
  r.method = "POST";
780
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
781
789
  r.headers["Content-Type"] = "application/json";
782
790
  });
783
791
  }
@@ -790,6 +798,7 @@ export class LavalinkNode {
790
798
  throw new SyntaxError("LavalinkNode requires 'host'");
791
799
  if (!this.options.port)
792
800
  throw new SyntaxError("LavalinkNode requires 'port'");
801
+ // TODO add more validations
793
802
  }
794
803
  /**
795
804
  * Sync the data of the player you make an action to lavalink to
@@ -854,11 +863,13 @@ export class LavalinkNode {
854
863
  const player = this.NodeManager.LavalinkManager.getPlayer(data.guildId);
855
864
  if (!player)
856
865
  return;
857
- if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false)
858
- return player.destroy(DestroyReasons.LavalinkNoVoice);
866
+ if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false) {
867
+ player.destroy(DestroyReasons.LavalinkNoVoice);
868
+ return;
869
+ }
859
870
  player.ping.ws = res?.voice?.ping || player?.ping.ws;
860
871
  }
861
- return true;
872
+ return;
862
873
  }
863
874
  /**
864
875
  * Get the rest Adress for making requests
@@ -892,6 +903,7 @@ export class LavalinkNode {
892
903
  return;
893
904
  }
894
905
  this.reconnectTimeout = setTimeout(() => {
906
+ this.reconnectTimeout = null;
895
907
  if (this.reconnectAttempts >= this.options.retryAmount) {
896
908
  const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
897
909
  this.NodeManager.emit("error", this, error);
@@ -927,7 +939,7 @@ export class LavalinkNode {
927
939
  this.isAlive = false;
928
940
  this.heartBeatPingTimestamp = performance.now();
929
941
  this.socket.ping();
930
- }, this.options.heartBeatInterval || 30000);
942
+ }, this.options.heartBeatInterval || 30_000);
931
943
  }
932
944
  if (this.reconnectTimeout)
933
945
  clearTimeout(this.reconnectTimeout);
@@ -948,6 +960,8 @@ export class LavalinkNode {
948
960
  clearInterval(this.heartBeatInterval);
949
961
  if (code === 1006 && !reason)
950
962
  reason = "Socket got terminated due to no ping connection";
963
+ if (code === 1000 && reason === "Node-Disconnect")
964
+ return; // manually disconnected and already emitted the event.
951
965
  this.NodeManager.emit("disconnect", this, { code, reason });
952
966
  if (code !== 1000 || reason !== "Node-Destroy")
953
967
  this.reconnect();
@@ -972,7 +986,14 @@ export class LavalinkNode {
972
986
  d = Buffer.concat(d);
973
987
  else if (d instanceof ArrayBuffer)
974
988
  d = Buffer.from(d);
975
- const payload = JSON.parse(d.toString());
989
+ let payload;
990
+ try {
991
+ payload = JSON.parse(d.toString());
992
+ }
993
+ catch (e) {
994
+ this.NodeManager.emit("error", this, e);
995
+ return;
996
+ }
976
997
  if (!payload.op)
977
998
  return;
978
999
  this.NodeManager.emit("raw", this, payload);
@@ -1003,7 +1024,7 @@ export class LavalinkNode {
1003
1024
  player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
1004
1025
  if (!player.createdTimeStamp && payload.state.time)
1005
1026
  player.createdTimeStamp = payload.state.time;
1006
- if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600000) || isAbsolute(player.queue.current?.info?.uri))) {
1027
+ if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600_000) || isAbsolute(player.queue.current?.info?.uri))) {
1007
1028
  player.filterManager.filterUpdatedState = false;
1008
1029
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1009
1030
  this.NodeManager.LavalinkManager.emit("debug", DebugEvents.PlayerUpdateFilterFixApply, {
@@ -1095,7 +1116,7 @@ export class LavalinkNode {
1095
1116
  }
1096
1117
  return;
1097
1118
  }
1098
- async getTrackOfPayload(payload) {
1119
+ getTrackOfPayload(payload) {
1099
1120
  return "track" in payload
1100
1121
  ? this.NodeManager.LavalinkManager.utils.buildTrack(payload.track, undefined)
1101
1122
  : null;
@@ -1116,7 +1137,7 @@ export class LavalinkNode {
1116
1137
  return;
1117
1138
  }
1118
1139
  if (!player.queue.current) {
1119
- player.queue.current = await this.getTrackOfPayload(payload);
1140
+ player.queue.current = this.getTrackOfPayload(payload);
1120
1141
  if (player.queue.current) {
1121
1142
  await player.queue.utils.save();
1122
1143
  }
@@ -1130,11 +1151,12 @@ export class LavalinkNode {
1130
1151
  }
1131
1152
  }
1132
1153
  }
1133
- return this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
1154
+ this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
1155
+ return;
1134
1156
  }
1135
1157
  /** @private util function for handling trackEnd event */
1136
1158
  async trackEnd(player, track, payload) {
1137
- const trackToUse = track || await this.getTrackOfPayload(payload);
1159
+ const trackToUse = track || this.getTrackOfPayload(payload);
1138
1160
  // If a track was forcibly played
1139
1161
  if (payload.reason === "replaced") {
1140
1162
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
@@ -1144,7 +1166,8 @@ export class LavalinkNode {
1144
1166
  functionLayer: "LavalinkNode > trackEnd()",
1145
1167
  });
1146
1168
  }
1147
- return this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1169
+ this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1170
+ return;
1148
1171
  }
1149
1172
  // If there are no songs in the queue
1150
1173
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
@@ -1158,7 +1181,10 @@ export class LavalinkNode {
1158
1181
  // fire event
1159
1182
  this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1160
1183
  // play track if autoSkip is true
1161
- return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
1184
+ if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1185
+ player.play({ noReplace: true });
1186
+ }
1187
+ return;
1162
1188
  }
1163
1189
  // remove tracks from the queue
1164
1190
  if (player.repeatMode !== "track" || player.get("internal_skipped"))
@@ -1176,7 +1202,10 @@ export class LavalinkNode {
1176
1202
  // fire event
1177
1203
  this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
1178
1204
  // play track if autoSkip is true
1179
- return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
1205
+ if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1206
+ player.play({ noReplace: true });
1207
+ }
1208
+ return;
1180
1209
  }
1181
1210
  /** @private util function for handling trackStuck event */
1182
1211
  async trackStuck(player, track, payload) {
@@ -1192,21 +1221,25 @@ export class LavalinkNode {
1192
1221
  functionLayer: "LavalinkNode > trackStuck()",
1193
1222
  });
1194
1223
  }
1195
- return player.destroy(DestroyReasons.TrackStuckMaxTracksErroredPerTime);
1224
+ player.destroy(DestroyReasons.TrackStuckMaxTracksErroredPerTime);
1225
+ return;
1196
1226
  }
1197
1227
  }
1198
- this.NodeManager.LavalinkManager.emit("trackStuck", player, track || await this.getTrackOfPayload(payload), payload);
1228
+ this.NodeManager.LavalinkManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
1199
1229
  // If there are no songs in the queue
1200
1230
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
1201
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1231
+ return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1202
1232
  // remove the current track, and enqueue the next one
1203
1233
  await queueTrackEnd(player);
1204
1234
  // if no track available, end queue
1205
1235
  if (!player.queue.current) {
1206
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1236
+ return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1207
1237
  }
1208
1238
  // play track if autoSkip is true
1209
- return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
1239
+ if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1240
+ player.play({ noReplace: true });
1241
+ }
1242
+ return;
1210
1243
  }
1211
1244
  /** @private util function for handling trackError event */
1212
1245
  async trackError(player, track, payload) {
@@ -1222,46 +1255,37 @@ export class LavalinkNode {
1222
1255
  functionLayer: "LavalinkNode > trackError()",
1223
1256
  });
1224
1257
  }
1225
- return player.destroy(DestroyReasons.TrackErrorMaxTracksErroredPerTime);
1258
+ player.destroy(DestroyReasons.TrackErrorMaxTracksErroredPerTime);
1259
+ return;
1226
1260
  }
1227
1261
  }
1228
- this.NodeManager.LavalinkManager.emit("trackError", player, track || await this.getTrackOfPayload(payload), payload);
1229
- return; // get's handled by trackEnd
1230
- // If there are no songs in the queue
1231
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
1232
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1233
- // remove the current track, and enqueue the next one
1234
- await queueTrackEnd(player);
1235
- // if no track available, end queue
1236
- if (!player.queue.current)
1237
- return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
1238
- // play track if autoSkip is true
1239
- return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
1262
+ this.NodeManager.LavalinkManager.emit("trackError", player, track || this.getTrackOfPayload(payload), payload);
1263
+ return;
1240
1264
  }
1241
1265
  /** @private util function for handling socketClosed event */
1242
1266
  socketClosed(player, payload) {
1243
1267
  this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
1244
- // i don't think this is needed.
1245
- // this.socket = null;
1246
- // // causing a socket reconnect
1247
- // this.connect();
1248
1268
  return;
1249
1269
  }
1250
1270
  /** @private util function for handling SponsorBlock Segmentloaded event */
1251
1271
  async SponsorBlockSegmentLoaded(player, track, payload) {
1252
- return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || await this.getTrackOfPayload(payload), payload);
1272
+ this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || this.getTrackOfPayload(payload), payload);
1273
+ return;
1253
1274
  }
1254
1275
  /** @private util function for handling SponsorBlock SegmentSkipped event */
1255
1276
  async SponsorBlockSegmentSkipped(player, track, payload) {
1256
- return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || await this.getTrackOfPayload(payload), payload);
1277
+ this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || this.getTrackOfPayload(payload), payload);
1278
+ return;
1257
1279
  }
1258
1280
  /** @private util function for handling SponsorBlock Chaptersloaded event */
1259
1281
  async SponsorBlockChaptersLoaded(player, track, payload) {
1260
- return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || await this.getTrackOfPayload(payload), payload);
1282
+ this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || this.getTrackOfPayload(payload), payload);
1283
+ return;
1261
1284
  }
1262
1285
  /** @private util function for handling SponsorBlock Chaptersstarted event */
1263
1286
  async SponsorBlockChapterStarted(player, track, payload) {
1264
- return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || await this.getTrackOfPayload(payload), payload);
1287
+ this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || this.getTrackOfPayload(payload), payload);
1288
+ return;
1265
1289
  }
1266
1290
  /**
1267
1291
  * Get the current sponsorblocks for the sponsorblock plugin
@@ -1408,8 +1432,10 @@ export class LavalinkNode {
1408
1432
  await player.queue.utils.save();
1409
1433
  }
1410
1434
  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) {
1411
- if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0)
1412
- return player.destroy(DestroyReasons.QueueEmpty);
1435
+ if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) {
1436
+ player.destroy(DestroyReasons.QueueEmpty);
1437
+ return;
1438
+ }
1413
1439
  else {
1414
1440
  if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1415
1441
  this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TriggerQueueEmptyInterval, {
@@ -1418,16 +1444,23 @@ export class LavalinkNode {
1418
1444
  functionLayer: "LavalinkNode > queueEnd() > destroyAfterMs",
1419
1445
  });
1420
1446
  }
1447
+ this.NodeManager.LavalinkManager.emit("playerQueueEmptyStart", player, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs);
1421
1448
  if (player.get("internal_queueempty")) {
1422
1449
  clearTimeout(player.get("internal_queueempty"));
1423
1450
  player.set("internal_queueempty", undefined);
1424
1451
  }
1425
1452
  player.set("internal_queueempty", setTimeout(() => {
1453
+ player.set("internal_queueempty", undefined);
1454
+ if (player.queue.current) {
1455
+ return this.NodeManager.LavalinkManager.emit("playerQueueEmptyCancel", player);
1456
+ }
1457
+ this.NodeManager.LavalinkManager.emit("playerQueueEmptyEnd", player);
1426
1458
  player.destroy(DestroyReasons.QueueEmpty);
1427
1459
  }, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
1428
1460
  }
1429
1461
  }
1430
- return this.NodeManager.LavalinkManager.emit("queueEnd", player, track, payload);
1462
+ this.NodeManager.LavalinkManager.emit("queueEnd", player, track, payload);
1463
+ return;
1431
1464
  }
1432
1465
  /**
1433
1466
  * Emitted whenever a line of lyrics gets emitted
@@ -1436,8 +1469,24 @@ export class LavalinkNode {
1436
1469
  * @param {Track} track The track that emitted the event
1437
1470
  * @param {LyricsLineEvent} payload The payload of the event
1438
1471
  */
1439
- LyricsLine(player, track, payload) {
1440
- return this.NodeManager.LavalinkManager.emit("LyricsLine", player, track, payload);
1472
+ async LyricsLine(player, track, payload) {
1473
+ if (!player.queue.current) {
1474
+ player.queue.current = this.getTrackOfPayload(payload);
1475
+ if (player.queue.current) {
1476
+ await player.queue.utils.save();
1477
+ }
1478
+ else {
1479
+ if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1480
+ this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackStartNoTrack, {
1481
+ state: "warn",
1482
+ message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
1483
+ functionLayer: "LavalinkNode > trackStart()",
1484
+ });
1485
+ }
1486
+ }
1487
+ }
1488
+ this.NodeManager.LavalinkManager.emit("LyricsLine", player, track, payload);
1489
+ return;
1441
1490
  }
1442
1491
  /**
1443
1492
  * Emitted whenever the lyrics for a track got found
@@ -1446,8 +1495,24 @@ export class LavalinkNode {
1446
1495
  * @param {Track} track The track that emitted the event
1447
1496
  * @param {LyricsFoundEvent} payload The payload of the event
1448
1497
  */
1449
- LyricsFound(player, track, payload) {
1450
- return this.NodeManager.LavalinkManager.emit("LyricsFound", player, track, payload);
1498
+ async LyricsFound(player, track, payload) {
1499
+ if (!player.queue.current) {
1500
+ player.queue.current = this.getTrackOfPayload(payload);
1501
+ if (player.queue.current) {
1502
+ await player.queue.utils.save();
1503
+ }
1504
+ else {
1505
+ if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1506
+ this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackStartNoTrack, {
1507
+ state: "warn",
1508
+ message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
1509
+ functionLayer: "LavalinkNode > trackStart()",
1510
+ });
1511
+ }
1512
+ }
1513
+ }
1514
+ this.NodeManager.LavalinkManager.emit("LyricsFound", player, track, payload);
1515
+ return;
1451
1516
  }
1452
1517
  /**
1453
1518
  * Emitted whenever the lyrics for a track got not found
@@ -1456,7 +1521,23 @@ export class LavalinkNode {
1456
1521
  * @param {Track} track The track that emitted the event
1457
1522
  * @param {LyricsNotFoundEvent} payload The payload of the event
1458
1523
  */
1459
- LyricsNotFound(player, track, payload) {
1460
- return this.NodeManager.LavalinkManager.emit("LyricsNotFound", player, track, payload);
1524
+ async LyricsNotFound(player, track, payload) {
1525
+ if (!player.queue.current) {
1526
+ player.queue.current = this.getTrackOfPayload(payload);
1527
+ if (player.queue.current) {
1528
+ await player.queue.utils.save();
1529
+ }
1530
+ else {
1531
+ if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
1532
+ this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackStartNoTrack, {
1533
+ state: "warn",
1534
+ message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
1535
+ functionLayer: "LavalinkNode > trackStart()",
1536
+ });
1537
+ }
1538
+ }
1539
+ }
1540
+ this.NodeManager.LavalinkManager.emit("LyricsNotFound", player, track, payload);
1541
+ return;
1461
1542
  }
1462
1543
  }
@@ -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