lavalink-client 2.3.5 → 2.4.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.
- package/README.md +73 -6
- package/dist/cjs/structures/Constants.d.ts +4 -0
- package/dist/cjs/structures/Constants.js +7 -2
- package/dist/cjs/structures/Filters.d.ts +24 -0
- package/dist/cjs/structures/Filters.js +34 -10
- package/dist/cjs/structures/LavalinkManager.d.ts +4 -5
- package/dist/cjs/structures/LavalinkManager.js +36 -14
- package/dist/cjs/structures/LavalinkManagerStatics.d.ts +2 -0
- package/dist/cjs/structures/LavalinkManagerStatics.js +11 -2
- package/dist/cjs/structures/Node.d.ts +107 -13
- package/dist/cjs/structures/Node.js +294 -76
- package/dist/cjs/structures/NodeManager.d.ts +2 -2
- package/dist/cjs/structures/NodeManager.js +19 -19
- package/dist/cjs/structures/Player.d.ts +51 -1
- package/dist/cjs/structures/Player.js +62 -0
- package/dist/cjs/structures/Queue.d.ts +9 -10
- package/dist/cjs/structures/Queue.js +3 -3
- package/dist/cjs/structures/Types/Manager.d.ts +59 -1
- package/dist/cjs/structures/Types/Node.d.ts +23 -1
- package/dist/cjs/structures/Types/Player.d.ts +5 -1
- package/dist/cjs/structures/Types/Queue.d.ts +6 -6
- package/dist/cjs/structures/Types/Track.d.ts +3 -1
- package/dist/cjs/structures/Types/Utils.d.ts +81 -8
- package/dist/cjs/structures/Utils.js +11 -9
- package/dist/esm/structures/Constants.d.ts +4 -0
- package/dist/esm/structures/Constants.js +6 -1
- package/dist/esm/structures/Filters.d.ts +24 -0
- package/dist/esm/structures/Filters.js +34 -10
- package/dist/esm/structures/LavalinkManager.d.ts +4 -5
- package/dist/esm/structures/LavalinkManager.js +36 -14
- package/dist/esm/structures/LavalinkManagerStatics.d.ts +2 -0
- package/dist/esm/structures/LavalinkManagerStatics.js +11 -2
- package/dist/esm/structures/Node.d.ts +107 -13
- package/dist/esm/structures/Node.js +294 -76
- package/dist/esm/structures/NodeManager.d.ts +2 -2
- package/dist/esm/structures/NodeManager.js +20 -20
- package/dist/esm/structures/Player.d.ts +51 -1
- package/dist/esm/structures/Player.js +62 -0
- package/dist/esm/structures/Queue.d.ts +9 -10
- package/dist/esm/structures/Queue.js +3 -3
- package/dist/esm/structures/Types/Manager.d.ts +59 -1
- package/dist/esm/structures/Types/Node.d.ts +23 -1
- package/dist/esm/structures/Types/Player.d.ts +5 -1
- package/dist/esm/structures/Types/Queue.d.ts +6 -6
- package/dist/esm/structures/Types/Track.d.ts +3 -1
- package/dist/esm/structures/Types/Utils.d.ts +81 -8
- package/dist/esm/structures/Utils.js +8 -6
- package/dist/types/structures/Constants.d.ts +4 -0
- package/dist/types/structures/Filters.d.ts +24 -0
- package/dist/types/structures/LavalinkManager.d.ts +4 -5
- package/dist/types/structures/LavalinkManagerStatics.d.ts +2 -0
- package/dist/types/structures/Node.d.ts +107 -13
- package/dist/types/structures/NodeManager.d.ts +2 -2
- package/dist/types/structures/Player.d.ts +51 -1
- package/dist/types/structures/Queue.d.ts +9 -10
- package/dist/types/structures/Types/Manager.d.ts +59 -1
- package/dist/types/structures/Types/Node.d.ts +23 -1
- package/dist/types/structures/Types/Player.d.ts +5 -1
- package/dist/types/structures/Types/Queue.d.ts +6 -6
- package/dist/types/structures/Types/Track.d.ts +3 -1
- package/dist/types/structures/Types/Utils.d.ts +81 -8
- package/package.json +29 -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:
|
|
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
|
|
148
|
+
const response = await fetch(urlToUse, options);
|
|
147
149
|
this.calls++;
|
|
148
|
-
return {
|
|
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 {
|
|
155
|
+
const { response, options } = await this.rawRequest(endpoint, modify);
|
|
165
156
|
if (["DELETE", "PUT"].includes(options.method))
|
|
166
157
|
return;
|
|
167
|
-
if (
|
|
168
|
-
throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${JSON.stringify(
|
|
169
|
-
return parseAsText ? await
|
|
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 {
|
|
265
|
-
const res = (
|
|
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
|
-
|
|
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
|
-
},
|
|
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
|
|
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
|
-
|
|
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,11 +596,108 @@ 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
|
}
|
|
592
602
|
};
|
|
603
|
+
lyrics = {
|
|
604
|
+
/**
|
|
605
|
+
* Get the lyrics of a track
|
|
606
|
+
* @param track the track to get the lyrics for
|
|
607
|
+
* @param skipTrackSource wether to skip the track source or not
|
|
608
|
+
* @returns the lyrics of the track
|
|
609
|
+
* @example
|
|
610
|
+
*
|
|
611
|
+
* ```ts
|
|
612
|
+
* const lyrics = await player.node.lyrics.get(track, true);
|
|
613
|
+
* // use it of player instead:
|
|
614
|
+
* // const lyrics = await player.getLyrics(track, true);
|
|
615
|
+
* ```
|
|
616
|
+
*/
|
|
617
|
+
get: async (track, skipTrackSource = false) => {
|
|
618
|
+
if (!this.sessionId)
|
|
619
|
+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
|
|
620
|
+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
|
|
621
|
+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
|
|
622
|
+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
|
|
623
|
+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
|
|
624
|
+
throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
|
|
625
|
+
const url = `/lyrics?track=${track.encoded}&skipTrackSource=${skipTrackSource}`;
|
|
626
|
+
return (await this.request(url));
|
|
627
|
+
},
|
|
628
|
+
/**
|
|
629
|
+
* Get the lyrics of the current playing track
|
|
630
|
+
*
|
|
631
|
+
* @param guildId the guild id of the player
|
|
632
|
+
* @param skipTrackSource wether to skip the track source or not
|
|
633
|
+
* @returns the lyrics of the current playing track
|
|
634
|
+
* @example
|
|
635
|
+
* ```ts
|
|
636
|
+
* const lyrics = await player.node.lyrics.getCurrent(guildId);
|
|
637
|
+
* // use it of player instead:
|
|
638
|
+
* // const lyrics = await player.getCurrentLyrics();
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
getCurrent: async (guildId, skipTrackSource = false) => {
|
|
642
|
+
if (!this.sessionId)
|
|
643
|
+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
|
|
644
|
+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
|
|
645
|
+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
|
|
646
|
+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
|
|
647
|
+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
|
|
648
|
+
throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
|
|
649
|
+
const url = `/sessions/${this.sessionId}/players/${guildId}/track/lyrics?skipTrackSource=${skipTrackSource}`;
|
|
650
|
+
return (await this.request(url));
|
|
651
|
+
},
|
|
652
|
+
/**
|
|
653
|
+
* subscribe to lyrics updates for a guild
|
|
654
|
+
* @param guildId the guild id of the player
|
|
655
|
+
* @returns request data of the request
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* ```ts
|
|
659
|
+
* await player.node.lyrics.subscribe(guildId);
|
|
660
|
+
* // use it of player instead:
|
|
661
|
+
* // const lyrics = await player.subscribeLyrics();
|
|
662
|
+
* ```
|
|
663
|
+
*/
|
|
664
|
+
subscribe: async (guildId) => {
|
|
665
|
+
if (!this.sessionId)
|
|
666
|
+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
|
|
667
|
+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
|
|
668
|
+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
|
|
669
|
+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
|
|
670
|
+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
|
|
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}`);
|
|
672
|
+
return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`, (options) => {
|
|
673
|
+
options.method = "POST";
|
|
674
|
+
});
|
|
675
|
+
},
|
|
676
|
+
/**
|
|
677
|
+
* unsubscribe from lyrics updates for a guild
|
|
678
|
+
* @param guildId the guild id of the player
|
|
679
|
+
* @returns request data of the request
|
|
680
|
+
*
|
|
681
|
+
* @example
|
|
682
|
+
* ```ts
|
|
683
|
+
* await player.node.lyrics.unsubscribe(guildId);
|
|
684
|
+
* // use it of player instead:
|
|
685
|
+
* // const lyrics = await player.unsubscribeLyrics();
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
unsubscribe: async (guildId) => {
|
|
689
|
+
if (!this.sessionId)
|
|
690
|
+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
|
|
691
|
+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
|
|
692
|
+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
|
|
693
|
+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
|
|
694
|
+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
|
|
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}`);
|
|
696
|
+
return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/unsubscribe`, (options) => {
|
|
697
|
+
options.method = "DELETE";
|
|
698
|
+
});
|
|
699
|
+
},
|
|
700
|
+
};
|
|
593
701
|
/**
|
|
594
702
|
* Request Lavalink statistics.
|
|
595
703
|
* @returns the lavalink node stats
|
|
@@ -662,9 +770,8 @@ class LavalinkNode {
|
|
|
662
770
|
unmarkFailedAddress: async (address) => {
|
|
663
771
|
if (!this.sessionId)
|
|
664
772
|
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
|
|
665
|
-
await this.request(`/routeplanner/free/address`, r => {
|
|
773
|
+
return await this.request(`/routeplanner/free/address`, r => {
|
|
666
774
|
r.method = "POST";
|
|
667
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
668
775
|
r.headers["Content-Type"] = "application/json";
|
|
669
776
|
r.body = JSON.stringify({ address });
|
|
670
777
|
});
|
|
@@ -683,7 +790,6 @@ class LavalinkNode {
|
|
|
683
790
|
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
|
|
684
791
|
return await this.request(`/routeplanner/free/all`, r => {
|
|
685
792
|
r.method = "POST";
|
|
686
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
687
793
|
r.headers["Content-Type"] = "application/json";
|
|
688
794
|
});
|
|
689
795
|
}
|
|
@@ -696,6 +802,7 @@ class LavalinkNode {
|
|
|
696
802
|
throw new SyntaxError("LavalinkNode requires 'host'");
|
|
697
803
|
if (!this.options.port)
|
|
698
804
|
throw new SyntaxError("LavalinkNode requires 'port'");
|
|
805
|
+
// TODO add more validations
|
|
699
806
|
}
|
|
700
807
|
/**
|
|
701
808
|
* Sync the data of the player you make an action to lavalink to
|
|
@@ -760,11 +867,13 @@ class LavalinkNode {
|
|
|
760
867
|
const player = this.NodeManager.LavalinkManager.getPlayer(data.guildId);
|
|
761
868
|
if (!player)
|
|
762
869
|
return;
|
|
763
|
-
if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false)
|
|
764
|
-
|
|
870
|
+
if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false) {
|
|
871
|
+
player.destroy(Constants_1.DestroyReasons.LavalinkNoVoice);
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
765
874
|
player.ping.ws = res?.voice?.ping || player?.ping.ws;
|
|
766
875
|
}
|
|
767
|
-
return
|
|
876
|
+
return;
|
|
768
877
|
}
|
|
769
878
|
/**
|
|
770
879
|
* Get the rest Adress for making requests
|
|
@@ -798,6 +907,7 @@ class LavalinkNode {
|
|
|
798
907
|
return;
|
|
799
908
|
}
|
|
800
909
|
this.reconnectTimeout = setTimeout(() => {
|
|
910
|
+
this.reconnectTimeout = null;
|
|
801
911
|
if (this.reconnectAttempts >= this.options.retryAmount) {
|
|
802
912
|
const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
|
|
803
913
|
this.NodeManager.emit("error", this, error);
|
|
@@ -833,7 +943,7 @@ class LavalinkNode {
|
|
|
833
943
|
this.isAlive = false;
|
|
834
944
|
this.heartBeatPingTimestamp = performance.now();
|
|
835
945
|
this.socket.ping();
|
|
836
|
-
}, this.options.heartBeatInterval ||
|
|
946
|
+
}, this.options.heartBeatInterval || 30_000);
|
|
837
947
|
}
|
|
838
948
|
if (this.reconnectTimeout)
|
|
839
949
|
clearTimeout(this.reconnectTimeout);
|
|
@@ -854,6 +964,8 @@ class LavalinkNode {
|
|
|
854
964
|
clearInterval(this.heartBeatInterval);
|
|
855
965
|
if (code === 1006 && !reason)
|
|
856
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.
|
|
857
969
|
this.NodeManager.emit("disconnect", this, { code, reason });
|
|
858
970
|
if (code !== 1000 || reason !== "Node-Destroy")
|
|
859
971
|
this.reconnect();
|
|
@@ -878,7 +990,14 @@ class LavalinkNode {
|
|
|
878
990
|
d = Buffer.concat(d);
|
|
879
991
|
else if (d instanceof ArrayBuffer)
|
|
880
992
|
d = Buffer.from(d);
|
|
881
|
-
|
|
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
|
+
}
|
|
882
1001
|
if (!payload.op)
|
|
883
1002
|
return;
|
|
884
1003
|
this.NodeManager.emit("raw", this, payload);
|
|
@@ -909,7 +1028,7 @@ class LavalinkNode {
|
|
|
909
1028
|
player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
|
|
910
1029
|
if (!player.createdTimeStamp && payload.state.time)
|
|
911
1030
|
player.createdTimeStamp = payload.state.time;
|
|
912
|
-
if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration ||
|
|
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))) {
|
|
913
1032
|
player.filterManager.filterUpdatedState = false;
|
|
914
1033
|
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
915
1034
|
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerUpdateFilterFixApply, {
|
|
@@ -986,13 +1105,22 @@ class LavalinkNode {
|
|
|
986
1105
|
case "ChapterStarted":
|
|
987
1106
|
this.SponsorBlockChapterStarted(player, player.queue.current, payload);
|
|
988
1107
|
break;
|
|
1108
|
+
case "LyricsLineEvent":
|
|
1109
|
+
this.LyricsLine(player, player.queue.current, payload);
|
|
1110
|
+
break;
|
|
1111
|
+
case "LyricsFoundEvent":
|
|
1112
|
+
this.LyricsFound(player, player.queue.current, payload);
|
|
1113
|
+
break;
|
|
1114
|
+
case "LyricsNotFoundEvent":
|
|
1115
|
+
this.LyricsNotFound(player, player.queue.current, payload);
|
|
1116
|
+
break;
|
|
989
1117
|
default:
|
|
990
1118
|
this.NodeManager.emit("error", this, new Error(`Node#event unknown event '${payload.type}'.`), payload);
|
|
991
1119
|
break;
|
|
992
1120
|
}
|
|
993
1121
|
return;
|
|
994
1122
|
}
|
|
995
|
-
|
|
1123
|
+
getTrackOfPayload(payload) {
|
|
996
1124
|
return "track" in payload
|
|
997
1125
|
? this.NodeManager.LavalinkManager.utils.buildTrack(payload.track, undefined)
|
|
998
1126
|
: null;
|
|
@@ -1013,7 +1141,7 @@ class LavalinkNode {
|
|
|
1013
1141
|
return;
|
|
1014
1142
|
}
|
|
1015
1143
|
if (!player.queue.current) {
|
|
1016
|
-
player.queue.current =
|
|
1144
|
+
player.queue.current = this.getTrackOfPayload(payload);
|
|
1017
1145
|
if (player.queue.current) {
|
|
1018
1146
|
await player.queue.utils.save();
|
|
1019
1147
|
}
|
|
@@ -1027,11 +1155,12 @@ class LavalinkNode {
|
|
|
1027
1155
|
}
|
|
1028
1156
|
}
|
|
1029
1157
|
}
|
|
1030
|
-
|
|
1158
|
+
this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
|
|
1159
|
+
return;
|
|
1031
1160
|
}
|
|
1032
1161
|
/** @private util function for handling trackEnd event */
|
|
1033
1162
|
async trackEnd(player, track, payload) {
|
|
1034
|
-
const trackToUse = track ||
|
|
1163
|
+
const trackToUse = track || this.getTrackOfPayload(payload);
|
|
1035
1164
|
// If a track was forcibly played
|
|
1036
1165
|
if (payload.reason === "replaced") {
|
|
1037
1166
|
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
@@ -1041,7 +1170,8 @@ class LavalinkNode {
|
|
|
1041
1170
|
functionLayer: "LavalinkNode > trackEnd()",
|
|
1042
1171
|
});
|
|
1043
1172
|
}
|
|
1044
|
-
|
|
1173
|
+
this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
1174
|
+
return;
|
|
1045
1175
|
}
|
|
1046
1176
|
// If there are no songs in the queue
|
|
1047
1177
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
@@ -1055,7 +1185,10 @@ class LavalinkNode {
|
|
|
1055
1185
|
// fire event
|
|
1056
1186
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
1057
1187
|
// play track if autoSkip is true
|
|
1058
|
-
|
|
1188
|
+
if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
|
|
1189
|
+
player.play({ noReplace: true });
|
|
1190
|
+
}
|
|
1191
|
+
return;
|
|
1059
1192
|
}
|
|
1060
1193
|
// remove tracks from the queue
|
|
1061
1194
|
if (player.repeatMode !== "track" || player.get("internal_skipped"))
|
|
@@ -1073,7 +1206,10 @@ class LavalinkNode {
|
|
|
1073
1206
|
// fire event
|
|
1074
1207
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
1075
1208
|
// play track if autoSkip is true
|
|
1076
|
-
|
|
1209
|
+
if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
|
|
1210
|
+
player.play({ noReplace: true });
|
|
1211
|
+
}
|
|
1212
|
+
return;
|
|
1077
1213
|
}
|
|
1078
1214
|
/** @private util function for handling trackStuck event */
|
|
1079
1215
|
async trackStuck(player, track, payload) {
|
|
@@ -1089,21 +1225,25 @@ class LavalinkNode {
|
|
|
1089
1225
|
functionLayer: "LavalinkNode > trackStuck()",
|
|
1090
1226
|
});
|
|
1091
1227
|
}
|
|
1092
|
-
|
|
1228
|
+
player.destroy(Constants_1.DestroyReasons.TrackStuckMaxTracksErroredPerTime);
|
|
1229
|
+
return;
|
|
1093
1230
|
}
|
|
1094
1231
|
}
|
|
1095
|
-
this.NodeManager.LavalinkManager.emit("trackStuck", player, track ||
|
|
1232
|
+
this.NodeManager.LavalinkManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
|
|
1096
1233
|
// If there are no songs in the queue
|
|
1097
1234
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
1098
|
-
return this.queueEnd(player, track ||
|
|
1235
|
+
return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
|
|
1099
1236
|
// remove the current track, and enqueue the next one
|
|
1100
1237
|
await (0, Utils_1.queueTrackEnd)(player);
|
|
1101
1238
|
// if no track available, end queue
|
|
1102
1239
|
if (!player.queue.current) {
|
|
1103
|
-
return this.queueEnd(player, track ||
|
|
1240
|
+
return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
|
|
1104
1241
|
}
|
|
1105
1242
|
// play track if autoSkip is true
|
|
1106
|
-
|
|
1243
|
+
if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
|
|
1244
|
+
player.play({ noReplace: true });
|
|
1245
|
+
}
|
|
1246
|
+
return;
|
|
1107
1247
|
}
|
|
1108
1248
|
/** @private util function for handling trackError event */
|
|
1109
1249
|
async trackError(player, track, payload) {
|
|
@@ -1119,46 +1259,37 @@ class LavalinkNode {
|
|
|
1119
1259
|
functionLayer: "LavalinkNode > trackError()",
|
|
1120
1260
|
});
|
|
1121
1261
|
}
|
|
1122
|
-
|
|
1262
|
+
player.destroy(Constants_1.DestroyReasons.TrackErrorMaxTracksErroredPerTime);
|
|
1263
|
+
return;
|
|
1123
1264
|
}
|
|
1124
1265
|
}
|
|
1125
|
-
this.NodeManager.LavalinkManager.emit("trackError", player, track ||
|
|
1126
|
-
return;
|
|
1127
|
-
// If there are no songs in the queue
|
|
1128
|
-
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
1129
|
-
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
1130
|
-
// remove the current track, and enqueue the next one
|
|
1131
|
-
await (0, Utils_1.queueTrackEnd)(player);
|
|
1132
|
-
// if no track available, end queue
|
|
1133
|
-
if (!player.queue.current)
|
|
1134
|
-
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
1135
|
-
// play track if autoSkip is true
|
|
1136
|
-
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;
|
|
1137
1268
|
}
|
|
1138
1269
|
/** @private util function for handling socketClosed event */
|
|
1139
1270
|
socketClosed(player, payload) {
|
|
1140
1271
|
this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
|
|
1141
|
-
// i don't think this is needed.
|
|
1142
|
-
// this.socket = null;
|
|
1143
|
-
// // causing a socket reconnect
|
|
1144
|
-
// this.connect();
|
|
1145
1272
|
return;
|
|
1146
1273
|
}
|
|
1147
1274
|
/** @private util function for handling SponsorBlock Segmentloaded event */
|
|
1148
1275
|
async SponsorBlockSegmentLoaded(player, track, payload) {
|
|
1149
|
-
|
|
1276
|
+
this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || this.getTrackOfPayload(payload), payload);
|
|
1277
|
+
return;
|
|
1150
1278
|
}
|
|
1151
1279
|
/** @private util function for handling SponsorBlock SegmentSkipped event */
|
|
1152
1280
|
async SponsorBlockSegmentSkipped(player, track, payload) {
|
|
1153
|
-
|
|
1281
|
+
this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || this.getTrackOfPayload(payload), payload);
|
|
1282
|
+
return;
|
|
1154
1283
|
}
|
|
1155
1284
|
/** @private util function for handling SponsorBlock Chaptersloaded event */
|
|
1156
1285
|
async SponsorBlockChaptersLoaded(player, track, payload) {
|
|
1157
|
-
|
|
1286
|
+
this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || this.getTrackOfPayload(payload), payload);
|
|
1287
|
+
return;
|
|
1158
1288
|
}
|
|
1159
1289
|
/** @private util function for handling SponsorBlock Chaptersstarted event */
|
|
1160
1290
|
async SponsorBlockChapterStarted(player, track, payload) {
|
|
1161
|
-
|
|
1291
|
+
this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || this.getTrackOfPayload(payload), payload);
|
|
1292
|
+
return;
|
|
1162
1293
|
}
|
|
1163
1294
|
/**
|
|
1164
1295
|
* Get the current sponsorblocks for the sponsorblock plugin
|
|
@@ -1305,8 +1436,10 @@ class LavalinkNode {
|
|
|
1305
1436
|
await player.queue.utils.save();
|
|
1306
1437
|
}
|
|
1307
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) {
|
|
1308
|
-
if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0)
|
|
1309
|
-
|
|
1439
|
+
if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) {
|
|
1440
|
+
player.destroy(Constants_1.DestroyReasons.QueueEmpty);
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1310
1443
|
else {
|
|
1311
1444
|
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1312
1445
|
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TriggerQueueEmptyInterval, {
|
|
@@ -1315,16 +1448,101 @@ class LavalinkNode {
|
|
|
1315
1448
|
functionLayer: "LavalinkNode > queueEnd() > destroyAfterMs",
|
|
1316
1449
|
});
|
|
1317
1450
|
}
|
|
1451
|
+
this.NodeManager.LavalinkManager.emit("playerQueueEmptyStart", player, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs);
|
|
1318
1452
|
if (player.get("internal_queueempty")) {
|
|
1319
1453
|
clearTimeout(player.get("internal_queueempty"));
|
|
1320
1454
|
player.set("internal_queueempty", undefined);
|
|
1321
1455
|
}
|
|
1322
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);
|
|
1323
1462
|
player.destroy(Constants_1.DestroyReasons.QueueEmpty);
|
|
1324
1463
|
}, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
|
|
1325
1464
|
}
|
|
1326
1465
|
}
|
|
1327
|
-
|
|
1466
|
+
this.NodeManager.LavalinkManager.emit("queueEnd", player, track, payload);
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Emitted whenever a line of lyrics gets emitted
|
|
1471
|
+
* @event
|
|
1472
|
+
* @param {Player} player The player that emitted the event
|
|
1473
|
+
* @param {Track} track The track that emitted the event
|
|
1474
|
+
* @param {LyricsLineEvent} payload The payload of the event
|
|
1475
|
+
*/
|
|
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;
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Emitted whenever the lyrics for a track got found
|
|
1497
|
+
* @event
|
|
1498
|
+
* @param {Player} player The player that emitted the event
|
|
1499
|
+
* @param {Track} track The track that emitted the event
|
|
1500
|
+
* @param {LyricsFoundEvent} payload The payload of the event
|
|
1501
|
+
*/
|
|
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;
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* Emitted whenever the lyrics for a track got not found
|
|
1523
|
+
* @event
|
|
1524
|
+
* @param {Player} player The player that emitted the event
|
|
1525
|
+
* @param {Track} track The track that emitted the event
|
|
1526
|
+
* @param {LyricsNotFoundEvent} payload The payload of the event
|
|
1527
|
+
*/
|
|
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;
|
|
1328
1546
|
}
|
|
1329
1547
|
}
|
|
1330
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
|