lavalink-client 2.2.2 → 2.3.0

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 (88) hide show
  1. package/README.md +95 -1
  2. package/dist/cjs/index.d.ts +7 -1
  3. package/dist/cjs/index.js +7 -1
  4. package/dist/cjs/structures/Constants.d.ts +40 -0
  5. package/dist/cjs/structures/Constants.js +244 -0
  6. package/dist/cjs/structures/CustomSearches/BandCampSearch.d.ts +2 -2
  7. package/dist/cjs/structures/Filters.d.ts +2 -217
  8. package/dist/cjs/structures/Filters.js +8 -232
  9. package/dist/cjs/structures/LavalinkManager.d.ts +31 -166
  10. package/dist/cjs/structures/LavalinkManager.js +59 -7
  11. package/dist/cjs/structures/LavalinkManagerStatics.d.ts +1 -1
  12. package/dist/cjs/structures/Node.d.ts +15 -156
  13. package/dist/cjs/structures/Node.js +131 -49
  14. package/dist/cjs/structures/NodeManager.d.ts +54 -52
  15. package/dist/cjs/structures/NodeManager.js +74 -4
  16. package/dist/cjs/structures/Player.d.ts +31 -124
  17. package/dist/cjs/structures/Player.js +77 -43
  18. package/dist/cjs/structures/Queue.d.ts +66 -42
  19. package/dist/cjs/structures/Queue.js +69 -11
  20. package/dist/cjs/structures/Types/Filters.d.ts +190 -0
  21. package/dist/cjs/structures/Types/Manager.d.ts +184 -0
  22. package/dist/cjs/structures/Types/Manager.js +2 -0
  23. package/dist/cjs/structures/Types/Node.d.ts +216 -0
  24. package/dist/cjs/structures/Types/Node.js +2 -0
  25. package/dist/cjs/structures/Types/Player.d.ts +108 -0
  26. package/dist/cjs/structures/Types/Player.js +2 -0
  27. package/dist/cjs/structures/Types/Queue.d.ts +34 -0
  28. package/dist/cjs/structures/Types/Queue.js +2 -0
  29. package/dist/cjs/structures/{Track.d.ts → Types/Track.d.ts} +3 -2
  30. package/dist/cjs/structures/Types/Track.js +2 -0
  31. package/dist/cjs/structures/Types/Utils.d.ts +367 -0
  32. package/dist/cjs/structures/Types/Utils.js +2 -0
  33. package/dist/cjs/structures/Utils.d.ts +13 -369
  34. package/dist/cjs/structures/Utils.js +35 -14
  35. package/dist/esm/index.d.ts +7 -1
  36. package/dist/esm/index.js +7 -1
  37. package/dist/esm/structures/Constants.d.ts +40 -0
  38. package/dist/esm/structures/Constants.js +241 -0
  39. package/dist/esm/structures/CustomSearches/BandCampSearch.d.ts +2 -2
  40. package/dist/esm/structures/Filters.d.ts +2 -217
  41. package/dist/esm/structures/Filters.js +3 -227
  42. package/dist/esm/structures/LavalinkManager.d.ts +31 -166
  43. package/dist/esm/structures/LavalinkManager.js +57 -5
  44. package/dist/esm/structures/LavalinkManagerStatics.d.ts +1 -1
  45. package/dist/esm/structures/Node.d.ts +15 -156
  46. package/dist/esm/structures/Node.js +122 -40
  47. package/dist/esm/structures/NodeManager.d.ts +54 -52
  48. package/dist/esm/structures/NodeManager.js +71 -1
  49. package/dist/esm/structures/Player.d.ts +31 -124
  50. package/dist/esm/structures/Player.js +76 -42
  51. package/dist/esm/structures/Queue.d.ts +66 -42
  52. package/dist/esm/structures/Queue.js +69 -11
  53. package/dist/esm/structures/Types/Filters.d.ts +190 -0
  54. package/dist/esm/structures/Types/Manager.d.ts +184 -0
  55. package/dist/esm/structures/Types/Manager.js +1 -0
  56. package/dist/esm/structures/Types/Node.d.ts +216 -0
  57. package/dist/esm/structures/Types/Node.js +1 -0
  58. package/dist/esm/structures/Types/Player.d.ts +108 -0
  59. package/dist/esm/structures/Types/Player.js +1 -0
  60. package/dist/esm/structures/Types/Queue.d.ts +34 -0
  61. package/dist/esm/structures/Types/Queue.js +1 -0
  62. package/dist/{types/structures → esm/structures/Types}/Track.d.ts +3 -2
  63. package/dist/esm/structures/Types/Track.js +1 -0
  64. package/dist/esm/structures/Types/Utils.d.ts +367 -0
  65. package/dist/esm/structures/Types/Utils.js +1 -0
  66. package/dist/esm/structures/Utils.d.ts +13 -369
  67. package/dist/esm/structures/Utils.js +35 -14
  68. package/dist/types/index.d.ts +7 -1
  69. package/dist/types/structures/Constants.d.ts +40 -0
  70. package/dist/types/structures/CustomSearches/BandCampSearch.d.ts +2 -2
  71. package/dist/types/structures/Filters.d.ts +2 -217
  72. package/dist/types/structures/LavalinkManager.d.ts +31 -166
  73. package/dist/types/structures/LavalinkManagerStatics.d.ts +1 -1
  74. package/dist/types/structures/Node.d.ts +15 -156
  75. package/dist/types/structures/NodeManager.d.ts +54 -52
  76. package/dist/types/structures/Player.d.ts +31 -124
  77. package/dist/types/structures/Queue.d.ts +66 -42
  78. package/dist/types/structures/Types/Filters.d.ts +190 -0
  79. package/dist/types/structures/Types/Manager.d.ts +184 -0
  80. package/dist/types/structures/Types/Node.d.ts +216 -0
  81. package/dist/types/structures/Types/Player.d.ts +108 -0
  82. package/dist/types/structures/Types/Queue.d.ts +34 -0
  83. package/dist/{esm/structures → types/structures/Types}/Track.d.ts +3 -2
  84. package/dist/types/structures/Types/Utils.d.ts +367 -0
  85. package/dist/types/structures/Utils.d.ts +13 -369
  86. package/package.json +1 -1
  87. /package/dist/cjs/structures/{Track.js → Types/Filters.js} +0 -0
  88. /package/dist/esm/structures/{Track.js → Types/Filters.js} +0 -0
@@ -1,162 +1,18 @@
1
- /// <reference types="node" />
2
- import internal from "stream";
3
- import { NodeManager } from "./NodeManager";
4
- import { DestroyReasonsType, Player } from "./Player";
5
- import { Track } from "./Track";
6
- import { Base64, InvalidLavalinkRestRequest, LavalinkPlayer, LavaSearchQuery, LavaSearchResponse, PlayerUpdateInfo, RoutePlanner, SearchQuery, SearchResult, Session } from "./Utils";
7
- /** Ability to manipulate fetch requests */
8
- export type ModifyRequest = (options: RequestInit & {
9
- path: string;
10
- extraQueryUrlParams?: URLSearchParams;
11
- }) => void;
12
- export declare const validSponsorBlocks: string[];
13
- export type SponsorBlockSegment = "sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "filler";
14
- /**
15
- * Node Options for creating a lavalink node
16
- */
17
- export interface LavalinkNodeOptions {
18
- /** The Lavalink Server-Ip / Domain-URL */
19
- host: string;
20
- /** The Lavalink Connection Port */
21
- port: number;
22
- /** The Lavalink Password / Authorization-Key */
23
- authorization: string;
24
- /** Does the Server use ssl (https) */
25
- secure?: boolean;
26
- /** RESUME THE PLAYER? by providing a sessionid on the node-creation */
27
- sessionId?: string;
28
- /** Add a Custom ID to the node, for later use */
29
- id?: string;
30
- /** Voice Regions of this Node */
31
- regions?: string[];
32
- /** The retryAmount for the node. */
33
- retryAmount?: number;
34
- /** The retryDelay for the node. */
35
- retryDelay?: number;
36
- /** signal for cancelling requests - default: AbortSignal.timeout(options.requestSignalTimeoutMS || 10000) - put <= 0 to disable */
37
- requestSignalTimeoutMS?: number;
38
- }
39
- /**
40
- * Memory Stats object from lavalink
41
- */
42
- export interface MemoryStats {
43
- /** The free memory of the allocated amount. */
44
- free: number;
45
- /** The used memory of the allocated amount. */
46
- used: number;
47
- /** The total allocated memory. */
48
- allocated: number;
49
- /** The reservable memory. */
50
- reservable: number;
51
- }
52
- /**
53
- * CPU Stats object from lavalink
54
- */
55
- export interface CPUStats {
56
- /** The core amount the host machine has. */
57
- cores: number;
58
- /** The system load. */
59
- systemLoad: number;
60
- /** The lavalink load. */
61
- lavalinkLoad: number;
62
- }
63
- /**
64
- * FrameStats Object from lavalink
65
- */
66
- export interface FrameStats {
67
- /** The amount of sent frames. */
68
- sent?: number;
69
- /** The amount of nulled frames. */
70
- nulled?: number;
71
- /** The amount of deficit frames. */
72
- deficit?: number;
73
- }
74
- /**
75
- * BaseNodeStats object from Lavalink
76
- */
77
- export interface BaseNodeStats {
78
- /** The amount of players on the node. */
79
- players: number;
80
- /** The amount of playing players on the node. */
81
- playingPlayers: number;
82
- /** The uptime for the node. */
83
- uptime: number;
84
- /** The memory stats for the node. */
85
- memory: MemoryStats;
86
- /** The cpu stats for the node. */
87
- cpu: CPUStats;
88
- /** The frame stats for the node. */
89
- frameStats: FrameStats;
90
- }
91
- /**
92
- * Interface for nodeStats from lavalink
93
- */
94
- export interface NodeStats extends BaseNodeStats {
95
- /** The frame stats for the node. */
96
- frameStats: FrameStats;
97
- }
98
- /**
99
- * Entire lavalink information object from lavalink
100
- */
101
- export interface LavalinkInfo {
102
- /** The version of this Lavalink server */
103
- version: VersionObject;
104
- /** The millisecond unix timestamp when this Lavalink jar was built */
105
- buildTime: number;
106
- /** The git information of this Lavalink server */
107
- git: GitObject;
108
- /** The JVM version this Lavalink server runs on */
109
- jvm: string;
110
- /** The Lavaplayer version being used by this server */
111
- lavaplayer: string;
112
- /** The enabled source managers for this server */
113
- sourceManagers: string[];
114
- /** The enabled filters for this server */
115
- filters: string[];
116
- /** The enabled plugins for this server */
117
- plugins: PluginObject[];
118
- }
119
- /**
120
- * Lavalink's version object from lavalink
121
- */
122
- export interface VersionObject {
123
- /** The full version string of this Lavalink server */
124
- semver: string;
125
- /** The major version of this Lavalink server */
126
- major: number;
127
- /** The minor version of this Lavalink server */
128
- minor: number;
129
- /** The patch version of this Lavalink server */
130
- patch: internal;
131
- /** The pre-release version according to semver as a . separated list of identifiers */
132
- preRelease?: string;
133
- /** The build metadata according to semver as a . separated list of identifiers */
134
- build?: string;
135
- }
136
- /**
137
- * Git information object from lavalink
138
- */
139
- export interface GitObject {
140
- /** The branch this Lavalink server was built on */
141
- branch: string;
142
- /** The commit this Lavalink server was built on */
143
- commit: string;
144
- /** The millisecond unix timestamp for when the commit was created */
145
- commitTime: string;
146
- }
147
- /**
148
- * Lavalink's plugins object from lavalink's plugin
149
- */
150
- export interface PluginObject {
151
- /** The name of the plugin */
152
- name: string;
153
- /** The version of the plugin */
154
- version: string;
155
- }
1
+ import type { Player } from "./Player";
2
+ import type { DestroyReasonsType } from "./Types/Player";
3
+ import type { Track } from "./Types/Track";
4
+ import type { Base64, InvalidLavalinkRestRequest, LavalinkPlayer, LavaSearchQuery, LavaSearchResponse, PlayerUpdateInfo, RoutePlanner, SearchQuery, SearchResult, Session } from "./Types/Utils";
5
+ import type { NodeManager } from "./NodeManager";
6
+ import type { BaseNodeStats, LavalinkInfo, LavalinkNodeOptions, ModifyRequest, NodeStats, SponsorBlockSegment } from "./Types/Node";
156
7
  /**
157
8
  * Lavalink Node creator class
158
9
  */
159
10
  export declare class LavalinkNode {
11
+ private heartBeatPingTimestamp;
12
+ private heartBeatPongTimestamp;
13
+ get heartBeatPing(): number;
14
+ private heartBeatInterval?;
15
+ private pingTimeout?;
160
16
  /** The provided Options of the Node */
161
17
  options: LavalinkNodeOptions;
162
18
  /** The amount of rest calls the node has made. */
@@ -300,6 +156,7 @@ export declare class LavalinkNode {
300
156
  * ```
301
157
  */
302
158
  connect(sessionId?: string): void;
159
+ private heartBeat;
303
160
  /**
304
161
  * Get the id of the node
305
162
  *
@@ -332,6 +189,7 @@ export declare class LavalinkNode {
332
189
  * ```
333
190
  */
334
191
  get connected(): boolean;
192
+ isAlive: boolean;
335
193
  /**
336
194
  * Returns the current ConnectionStatus
337
195
  *
@@ -356,7 +214,7 @@ export declare class LavalinkNode {
356
214
  * const playersOfLavalink = await node?.fetchAllPlayers();
357
215
  * ```
358
216
  */
359
- fetchAllPlayers(): Promise<LavalinkPlayer[]>;
217
+ fetchAllPlayers(): Promise<LavalinkPlayer[] | InvalidLavalinkRestRequest>;
360
218
  /**
361
219
  * Gets specific Player Information
362
220
  * @returns lavalink player object if player exists on lavalink
@@ -517,6 +375,7 @@ export declare class LavalinkNode {
517
375
  private message;
518
376
  /** @private middleware util function for handling all kind of events from websocket */
519
377
  private handleEvent;
378
+ private getTrackOfPayload;
520
379
  /** @private util function for handling trackStart event */
521
380
  private trackStart;
522
381
  /** @private util function for handling trackEnd event */
@@ -1,12 +1,18 @@
1
1
  import { isAbsolute } from "path";
2
2
  import WebSocket from "ws";
3
- import { DestroyReasons } from "./Player";
3
+ import { DestroyReasons, validSponsorBlocks } from "./Constants";
4
4
  import { NodeSymbol, queueTrackEnd } from "./Utils";
5
- export const validSponsorBlocks = ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "filler"];
6
5
  /**
7
6
  * Lavalink Node creator class
8
7
  */
9
8
  export class LavalinkNode {
9
+ heartBeatPingTimestamp = 0;
10
+ heartBeatPongTimestamp = 0;
11
+ get heartBeatPing() {
12
+ return this.heartBeatPongTimestamp - this.heartBeatPingTimestamp;
13
+ }
14
+ heartBeatInterval;
15
+ pingTimeout;
10
16
  /** The provided Options of the Node */
11
17
  options;
12
18
  /** The amount of rest calls the node has made. */
@@ -66,8 +72,11 @@ export class LavalinkNode {
66
72
  this.options = {
67
73
  secure: false,
68
74
  retryAmount: 5,
69
- retryDelay: 30e3,
75
+ retryDelay: 10e3,
70
76
  requestSignalTimeoutMS: 10000,
77
+ heartBeatInterval: 30000,
78
+ closeOnError: true,
79
+ enablePingOnStatsCheck: true,
71
80
  ...options
72
81
  };
73
82
  this.NodeManager = manager;
@@ -146,6 +155,8 @@ export class LavalinkNode {
146
155
  * ```
147
156
  */
148
157
  async request(endpoint, modify, parseAsText = false) {
158
+ if (!this.connected)
159
+ throw new Error("The node is not connected to the Lavalink Server!, Please call node.connect() first!");
149
160
  const { request, options } = await this.rawRequest(endpoint, modify);
150
161
  if (["DELETE", "PUT"].includes(options.method))
151
162
  return;
@@ -230,7 +241,7 @@ export class LavalinkNode {
230
241
  if (Query.source)
231
242
  this.NodeManager.LavalinkManager.utils.validateSourceString(this, Query.source);
232
243
  if (/^https?:\/\//.test(Query.query))
233
- return await this.search({ query: Query.query, source: Query.source }, requestUser);
244
+ return this.search({ query: Query.query, source: Query.source }, requestUser);
234
245
  if (!["spsearch", "sprec", "amsearch", "dzsearch", "dzisrc", "ytmsearch", "ytsearch"].includes(Query.source))
235
246
  throw new SyntaxError(`Query.source must be a source from LavaSrc: "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "ytmsearch" | "ytsearch"`);
236
247
  if (!this.info.plugins.find(v => v.name === "lavasearch-plugin"))
@@ -292,7 +303,7 @@ export class LavalinkNode {
292
303
  async destroyPlayer(guildId) {
293
304
  if (!this.sessionId)
294
305
  throw new Error("The Lavalink-Node is either not ready, or not up to date!");
295
- return await this.request(`/sessions/${this.sessionId}/players/${guildId}`, r => { r.method = "DELETE"; });
306
+ return this.request(`/sessions/${this.sessionId}/players/${guildId}`, r => { r.method = "DELETE"; });
296
307
  }
297
308
  /**
298
309
  * Connect to the Lavalink Node
@@ -324,6 +335,17 @@ export class LavalinkNode {
324
335
  this.socket.on("close", (code, reason) => this.close(code, reason?.toString()));
325
336
  this.socket.on("message", this.message.bind(this));
326
337
  this.socket.on("error", this.error.bind(this));
338
+ // this.socket.on("ping", () => this.heartBeat("ping")); // lavalink doesn'T send ping periodically, therefore we use the stats message
339
+ }
340
+ heartBeat() {
341
+ if (this.pingTimeout)
342
+ clearTimeout(this.pingTimeout);
343
+ this.pingTimeout = setTimeout(() => {
344
+ if (!this.socket)
345
+ return console.error("Node-Ping-Acknowledge-Timeout - Socket not available - maybe reconnecting?");
346
+ this.isAlive = false;
347
+ this.socket.terminate();
348
+ }, 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
327
349
  }
328
350
  /**
329
351
  * Get the id of the node
@@ -384,6 +406,7 @@ export class LavalinkNode {
384
406
  return false;
385
407
  return this.socket.readyState === WebSocket.OPEN;
386
408
  }
409
+ isAlive = false;
387
410
  /**
388
411
  * Returns the current ConnectionStatus
389
412
  *
@@ -415,11 +438,7 @@ export class LavalinkNode {
415
438
  async fetchAllPlayers() {
416
439
  if (!this.sessionId)
417
440
  throw new Error("The Lavalink-Node is either not ready, or not up to date!");
418
- const players = await this.request(`/sessions/${this.sessionId}/players`);
419
- if (!Array.isArray(players))
420
- return [];
421
- else
422
- return players;
441
+ return this.request(`/sessions/${this.sessionId}/players`) || [];
423
442
  }
424
443
  /**
425
444
  * Gets specific Player Information
@@ -434,7 +453,7 @@ export class LavalinkNode {
434
453
  async fetchPlayer(guildId) {
435
454
  if (!this.sessionId)
436
455
  throw new Error("The Lavalink-Node is either not ready, or not up to date!");
437
- return await this.request(`/sessions/${this.sessionId}/players/${guildId}`);
456
+ return this.request(`/sessions/${this.sessionId}/players/${guildId}`);
438
457
  }
439
458
  /**
440
459
  * Updates the session with and enables/disables resuming and timeout
@@ -460,7 +479,7 @@ export class LavalinkNode {
460
479
  enabled: typeof resuming === "boolean" ? resuming : false,
461
480
  timeout: typeof resuming === "boolean" && resuming === true ? timeout : null,
462
481
  };
463
- return await this.request(`/sessions/${this.sessionId}`, r => {
482
+ return this.request(`/sessions/${this.sessionId}`, r => {
464
483
  r.method = "PATCH";
465
484
  r.headers = { Authorization: this.options.authorization, 'Content-Type': 'application/json' };
466
485
  r.body = JSON.stringify(data);
@@ -706,6 +725,7 @@ export class LavalinkNode {
706
725
  * ```
707
726
  */
708
727
  reconnect(instaReconnect = false) {
728
+ this.NodeManager.emit("reconnectinprogress", this);
709
729
  if (instaReconnect) {
710
730
  if (this.reconnectAttempts >= this.options.retryAmount) {
711
731
  const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
@@ -734,6 +754,29 @@ export class LavalinkNode {
734
754
  }
735
755
  /** @private util function for handling opening events from websocket */
736
756
  async open() {
757
+ this.isAlive = true;
758
+ // trigger heartbeat-ping timeout - this is to check wether the client lost connection without knowing it
759
+ if (this.options.enablePingOnStatsCheck)
760
+ this.heartBeat();
761
+ if (this.heartBeatInterval)
762
+ clearInterval(this.heartBeatInterval);
763
+ if (this.options.heartBeatInterval > 0) {
764
+ // everytime a pong happens, set this.isAlive to true
765
+ this.socket.on("pong", () => {
766
+ this.heartBeatPongTimestamp = performance.now();
767
+ this.isAlive = true;
768
+ });
769
+ // every x ms send a ping to lavalink to retrieve a pong later on
770
+ this.heartBeatInterval = setInterval(() => {
771
+ if (!this.socket)
772
+ return console.error("Node-Heartbeat-Interval - Socket not available - maybe reconnecting?");
773
+ if (!this.isAlive)
774
+ this.close(500, "Node-Heartbeat-Timeout");
775
+ this.isAlive = false;
776
+ this.heartBeatPingTimestamp = performance.now();
777
+ this.socket.ping();
778
+ }, this.options.heartBeatInterval || 30000);
779
+ }
737
780
  if (this.reconnectTimeout)
738
781
  clearTimeout(this.reconnectTimeout);
739
782
  // reset the reconnect attempts amount
@@ -747,6 +790,12 @@ export class LavalinkNode {
747
790
  }
748
791
  /** @private util function for handling closing events from websocket */
749
792
  close(code, reason) {
793
+ if (this.pingTimeout)
794
+ clearTimeout(this.pingTimeout);
795
+ if (this.heartBeatInterval)
796
+ clearInterval(this.heartBeatInterval);
797
+ if (code === 1006 && !reason)
798
+ reason = "Socket got terminated due to no ping connection";
750
799
  this.NodeManager.emit("disconnect", this, { code, reason });
751
800
  if (code !== 1000 || reason !== "Node-Destroy")
752
801
  this.reconnect();
@@ -756,6 +805,14 @@ export class LavalinkNode {
756
805
  if (!error)
757
806
  return;
758
807
  this.NodeManager.emit("error", this, error);
808
+ if (this.options.closeOnError) {
809
+ if (this.heartBeatInterval)
810
+ clearInterval(this.heartBeatInterval);
811
+ if (this.pingTimeout)
812
+ clearTimeout(this.pingTimeout);
813
+ this.socket?.close(500, "Node-Error - Force Reconnect");
814
+ }
815
+ ;
759
816
  }
760
817
  /** @private util function for handling message events from websocket */
761
818
  async message(d) {
@@ -769,6 +826,8 @@ export class LavalinkNode {
769
826
  this.NodeManager.emit("raw", this, payload);
770
827
  switch (payload.op) {
771
828
  case "stats":
829
+ if (this.options.enablePingOnStatsCheck)
830
+ this.heartBeat(); // lavalink doesn'T send "ping" periodically, therefore we use the stats message to check for a ping
772
831
  delete payload.op;
773
832
  this.stats = { ...payload };
774
833
  break;
@@ -798,7 +857,13 @@ export class LavalinkNode {
798
857
  this.sessionId = payload.sessionId;
799
858
  this.resuming.enabled = payload.resumed;
800
859
  if (payload.resumed === true) {
801
- this.NodeManager.emit("resumed", this, payload, await this.fetchAllPlayers());
860
+ try {
861
+ this.NodeManager.emit("resumed", this, payload, await this.fetchAllPlayers());
862
+ }
863
+ catch (e) {
864
+ console.error("Failed to fetch players for resumed event, falling back without players array", e);
865
+ this.NodeManager.emit("resumed", this, payload, []);
866
+ }
802
867
  }
803
868
  break;
804
869
  default:
@@ -808,7 +873,7 @@ export class LavalinkNode {
808
873
  }
809
874
  /** @private middleware util function for handling all kind of events from websocket */
810
875
  async handleEvent(payload) {
811
- if (!payload.guildId)
876
+ if (!payload?.guildId)
812
877
  return;
813
878
  const player = this.NodeManager.LavalinkManager.getPlayer(payload.guildId);
814
879
  if (!player)
@@ -847,39 +912,51 @@ export class LavalinkNode {
847
912
  }
848
913
  return;
849
914
  }
915
+ async getTrackOfPayload(payload) {
916
+ return "track" in payload
917
+ ? this.NodeManager.LavalinkManager.utils.buildTrack(payload.track, undefined)
918
+ : null;
919
+ }
850
920
  /** @private util function for handling trackStart event */
851
- trackStart(player, track, payload) {
921
+ async trackStart(player, track, payload) {
852
922
  player.playing = true;
853
923
  player.paused = false;
854
924
  // don't emit the event if previous track == new track aka track loop
855
925
  if (this.NodeManager.LavalinkManager.options?.emitNewSongsOnly === true && player.queue.previous[0]?.info?.identifier === track?.info?.identifier)
856
926
  return;
857
- return this.NodeManager.LavalinkManager.emit("trackStart", player, track, payload);
927
+ if (!player.queue.current) {
928
+ player.queue.current = await this.getTrackOfPayload(payload);
929
+ if (player.queue.current)
930
+ await player.queue.utils.save();
931
+ }
932
+ return this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
858
933
  }
859
934
  /** @private util function for handling trackEnd event */
860
935
  async trackEnd(player, track, payload) {
936
+ const trackToUse = track || await this.getTrackOfPayload(payload);
937
+ // If a track was forcibly played
938
+ if (payload.reason === "replaced") {
939
+ return this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
940
+ }
861
941
  // If there are no songs in the queue
862
942
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
863
943
  return this.queueEnd(player, track, payload);
864
- // If a track was forcibly played
865
- if (payload.reason === "replaced")
866
- return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
867
944
  // If a track had an error while starting
868
945
  if (["loadFailed", "cleanup"].includes(payload.reason)) {
869
946
  await queueTrackEnd(player);
870
947
  // if no track available, end queue
871
948
  if (!player.queue.current)
872
- return this.queueEnd(player, track, payload);
949
+ return this.queueEnd(player, trackToUse, payload);
873
950
  // fire event
874
- this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
951
+ this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
875
952
  // play track if autoSkip is true
876
953
  return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
877
954
  }
878
955
  // remove tracks from the queue
879
956
  if (player.repeatMode !== "track" || player.get("internal_skipped"))
880
957
  await queueTrackEnd(player);
881
- else if (player.queue.current && !player.queue.current?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
882
- player.queue.previous.unshift(player.queue.current);
958
+ else if (trackToUse && !trackToUse?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
959
+ player.queue.previous.unshift(trackToUse);
883
960
  if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
884
961
  player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
885
962
  await player.queue.utils.save();
@@ -887,60 +964,65 @@ export class LavalinkNode {
887
964
  player.set("internal_skipped", false);
888
965
  // if no track available, end queue
889
966
  if (!player.queue.current)
890
- return this.queueEnd(player, track, payload);
967
+ return this.queueEnd(player, trackToUse, payload);
891
968
  // fire event
892
- this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
969
+ this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
893
970
  // play track if autoSkip is true
894
971
  return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
895
972
  }
896
973
  /** @private util function for handling trackStuck event */
897
974
  async trackStuck(player, track, payload) {
898
- this.NodeManager.LavalinkManager.emit("trackStuck", player, track, payload);
975
+ this.NodeManager.LavalinkManager.emit("trackStuck", player, track || await this.getTrackOfPayload(payload), payload);
899
976
  // If there are no songs in the queue
900
977
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
901
- return this.queueEnd(player, track, payload);
978
+ return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
902
979
  // remove the current track, and enqueue the next one
903
980
  await queueTrackEnd(player);
904
981
  // if no track available, end queue
905
982
  if (!player.queue.current)
906
- return this.queueEnd(player, track, payload);
983
+ return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
907
984
  // play track if autoSkip is true
908
985
  return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
909
986
  }
910
987
  /** @private util function for handling trackError event */
911
988
  async trackError(player, track, payload) {
912
- this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
989
+ this.NodeManager.LavalinkManager.emit("trackError", player, track || await this.getTrackOfPayload(payload), payload);
913
990
  return; // get's handled by trackEnd
914
991
  // If there are no songs in the queue
915
992
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
916
- return this.queueEnd(player, track, payload);
993
+ return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
917
994
  // remove the current track, and enqueue the next one
918
995
  await queueTrackEnd(player);
919
996
  // if no track available, end queue
920
997
  if (!player.queue.current)
921
- return this.queueEnd(player, track, payload);
998
+ return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
922
999
  // play track if autoSkip is true
923
1000
  return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
924
1001
  }
925
1002
  /** @private util function for handling socketClosed event */
926
1003
  socketClosed(player, payload) {
927
- return this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
1004
+ this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
1005
+ // i don't think this is needed.
1006
+ // this.socket = null;
1007
+ // // causing a socket reconnect
1008
+ // this.connect();
1009
+ return;
928
1010
  }
929
1011
  /** @private util function for handling SponsorBlock Segmentloaded event */
930
- SponsorBlockSegmentLoaded(player, track, payload) {
931
- return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track, payload);
1012
+ async SponsorBlockSegmentLoaded(player, track, payload) {
1013
+ return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || await this.getTrackOfPayload(payload), payload);
932
1014
  }
933
1015
  /** @private util function for handling SponsorBlock SegmentSkipped event */
934
- SponsorBlockSegmentSkipped(player, track, payload) {
935
- return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track, payload);
1016
+ async SponsorBlockSegmentSkipped(player, track, payload) {
1017
+ return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || await this.getTrackOfPayload(payload), payload);
936
1018
  }
937
1019
  /** @private util function for handling SponsorBlock Chaptersloaded event */
938
- SponsorBlockChaptersLoaded(player, track, payload) {
939
- return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track, payload);
1020
+ async SponsorBlockChaptersLoaded(player, track, payload) {
1021
+ return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || await this.getTrackOfPayload(payload), payload);
940
1022
  }
941
1023
  /** @private util function for handling SponsorBlock Chaptersstarted event */
942
- SponsorBlockChapterStarted(player, track, payload) {
943
- return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track, payload);
1024
+ async SponsorBlockChapterStarted(player, track, payload) {
1025
+ return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || await this.getTrackOfPayload(payload), payload);
944
1026
  }
945
1027
  /**
946
1028
  * Get the current sponsorblocks for the sponsorblock plugin