lavalink-client 2.4.4 → 2.4.6
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 +11 -0
- package/dist/cjs/structures/Constants.d.ts +2 -0
- package/dist/cjs/structures/Constants.js +2 -0
- package/dist/cjs/structures/Node.d.ts +7 -1
- package/dist/cjs/structures/Node.js +85 -16
- package/dist/cjs/structures/NodeManager.d.ts +12 -1
- package/dist/cjs/structures/NodeManager.js +16 -2
- package/dist/cjs/structures/Player.d.ts +2 -1
- package/dist/cjs/structures/Player.js +81 -18
- package/dist/esm/structures/Constants.d.ts +2 -0
- package/dist/esm/structures/Constants.js +2 -0
- package/dist/esm/structures/Node.d.ts +7 -1
- package/dist/esm/structures/Node.js +85 -16
- package/dist/esm/structures/NodeManager.d.ts +12 -1
- package/dist/esm/structures/NodeManager.js +16 -2
- package/dist/esm/structures/Player.d.ts +2 -1
- package/dist/esm/structures/Player.js +81 -18
- package/dist/types/structures/Constants.d.ts +2 -0
- package/dist/types/structures/Node.d.ts +7 -1
- package/dist/types/structures/NodeManager.d.ts +12 -1
- package/dist/types/structures/Player.d.ts +2 -1
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -808,3 +808,14 @@ if(previousTrack) {
|
|
|
808
808
|
- Added the try to play the next track if there is no current track
|
|
809
809
|
- *There was a problem trying to auto-reconnect on-Disconnect while the queue was empty, which caused the player to get destroyed by that and log the error in console "`There is no Track in the Queue, nor provided in the PlayOptions`"*
|
|
810
810
|
- *Now you have to handle that case manually if you want to or set autoReconnectOnlyWithTracks to false (default)*
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
## **Version 2.4.4 - Version 2.4.6**
|
|
814
|
+
- `player.changeNode()` is fixed and works - thanks to @PandaIN95
|
|
815
|
+
- The code got re-formatted and re-structured, no code-changes are needed to be made, but it's now cleaner & more readable in some areas
|
|
816
|
+
- The same for the testbot Folder(s), also it imports lavalink-client directly, so you can just copy it and move on from it.
|
|
817
|
+
- Some minor Fixess:
|
|
818
|
+
- Autoplay sometimes doesn't get called when previousAutoplay call failed.
|
|
819
|
+
- remove structuredClone so that it works in bun more stable
|
|
820
|
+
- Player Options Validation also allows single property objects
|
|
821
|
+
- Some typos were fixed
|
|
@@ -49,6 +49,8 @@ export declare enum DestroyReasons {
|
|
|
49
49
|
NodeReconnectFail = "NodeReconnectFail",
|
|
50
50
|
Disconnected = "Disconnected",
|
|
51
51
|
PlayerReconnectFail = "PlayerReconnectFail",
|
|
52
|
+
PlayerChangeNodeFail = "PlayerChangeNodeFail",
|
|
53
|
+
PlayerChangeNodeFailNoEligibleNode = "PlayerChangeNodeFailNoEligibleNode",
|
|
52
54
|
ChannelDeleted = "ChannelDeleted",
|
|
53
55
|
DisconnectAllNodes = "DisconnectAllNodes",
|
|
54
56
|
ReconnectAllNodes = "ReconnectAllNodes",
|
|
@@ -53,6 +53,8 @@ var DestroyReasons;
|
|
|
53
53
|
DestroyReasons["NodeReconnectFail"] = "NodeReconnectFail";
|
|
54
54
|
DestroyReasons["Disconnected"] = "Disconnected";
|
|
55
55
|
DestroyReasons["PlayerReconnectFail"] = "PlayerReconnectFail";
|
|
56
|
+
DestroyReasons["PlayerChangeNodeFail"] = "PlayerChangeNodeFail";
|
|
57
|
+
DestroyReasons["PlayerChangeNodeFailNoEligibleNode"] = "PlayerChangeNodeFailNoEligibleNode";
|
|
56
58
|
DestroyReasons["ChannelDeleted"] = "ChannelDeleted";
|
|
57
59
|
DestroyReasons["DisconnectAllNodes"] = "DisconnectAllNodes";
|
|
58
60
|
DestroyReasons["ReconnectAllNodes"] = "ReconnectAllNodes";
|
|
@@ -173,14 +173,20 @@ export declare class LavalinkNode {
|
|
|
173
173
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
174
174
|
* @param destroyReason Destroy Reason to use when destroying the players
|
|
175
175
|
* @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
|
|
176
|
+
* @param movePlayers whether to movePlayers to different eligible connected node. If false players won't be moved @default false
|
|
176
177
|
* @returns void
|
|
177
178
|
*
|
|
178
179
|
* @example
|
|
180
|
+
* Destroys node and its players
|
|
179
181
|
* ```ts
|
|
180
182
|
* player.node.destroy("custom Player Destroy Reason", true);
|
|
181
183
|
* ```
|
|
184
|
+
* destroys only the node and moves its players to different connected node.
|
|
185
|
+
* ```ts
|
|
186
|
+
* player.node.destroy("custom Player Destroy Reason", true, true);
|
|
187
|
+
* ```
|
|
182
188
|
*/
|
|
183
|
-
destroy(destroyReason?: DestroyReasonsType, deleteNode?: boolean): void;
|
|
189
|
+
destroy(destroyReason?: DestroyReasonsType, deleteNode?: boolean, movePlayers?: boolean): void;
|
|
184
190
|
/**
|
|
185
191
|
* Disconnects the Node-Connection (Websocket)
|
|
186
192
|
* @param disconnectReason Disconnect Reason to use when disconnecting Node
|
|
@@ -412,32 +412,94 @@ class LavalinkNode {
|
|
|
412
412
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
413
413
|
* @param destroyReason Destroy Reason to use when destroying the players
|
|
414
414
|
* @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
|
|
415
|
+
* @param movePlayers whether to movePlayers to different eligible connected node. If false players won't be moved @default false
|
|
415
416
|
* @returns void
|
|
416
417
|
*
|
|
417
418
|
* @example
|
|
419
|
+
* Destroys node and its players
|
|
418
420
|
* ```ts
|
|
419
421
|
* player.node.destroy("custom Player Destroy Reason", true);
|
|
420
422
|
* ```
|
|
423
|
+
* destroys only the node and moves its players to different connected node.
|
|
424
|
+
* ```ts
|
|
425
|
+
* player.node.destroy("custom Player Destroy Reason", true, true);
|
|
426
|
+
* ```
|
|
421
427
|
*/
|
|
422
|
-
destroy(destroyReason, deleteNode = true) {
|
|
428
|
+
destroy(destroyReason, deleteNode = true, movePlayers = false) {
|
|
423
429
|
if (!this.connected)
|
|
424
430
|
return;
|
|
425
431
|
const players = this.NodeManager.LavalinkManager.players.filter(p => p.node.id === this.id);
|
|
426
|
-
if (players)
|
|
427
|
-
|
|
428
|
-
|
|
432
|
+
if (players.size) {
|
|
433
|
+
const enableDebugEvents = this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents;
|
|
434
|
+
const handlePlayerOperations = () => {
|
|
435
|
+
if (movePlayers) {
|
|
436
|
+
const nodeToMove = Array.from(this.NodeManager.leastUsedNodes("playingPlayers"))
|
|
437
|
+
.find(n => n.connected && n.options.id !== this.id);
|
|
438
|
+
if (nodeToMove) {
|
|
439
|
+
return Promise.allSettled(Array.from(players.values()).map(player => player.changeNode(nodeToMove.options.id)
|
|
440
|
+
.catch(error => {
|
|
441
|
+
if (enableDebugEvents) {
|
|
442
|
+
console.error(`Node > destroy() Failed to move player ${player.guildId}: ${error.message}`);
|
|
443
|
+
}
|
|
444
|
+
return player.destroy(error.message ?? Constants_1.DestroyReasons.PlayerChangeNodeFail)
|
|
445
|
+
.catch(destroyError => {
|
|
446
|
+
if (enableDebugEvents) {
|
|
447
|
+
console.error(`Node > destroy() Failed to destroy player ${player.guildId} after move failure: ${destroyError.message}`);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
})));
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
return Promise.allSettled(Array.from(players.values()).map(player => player.destroy(Constants_1.DestroyReasons.PlayerChangeNodeFailNoEligibleNode)
|
|
454
|
+
.catch(error => {
|
|
455
|
+
if (enableDebugEvents) {
|
|
456
|
+
console.error(`Node > destroy() Failed to destroy player ${player.guildId}: ${error.message}`);
|
|
457
|
+
}
|
|
458
|
+
})));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
return Promise.allSettled(Array.from(players.values()).map(player => player.destroy(destroyReason || Constants_1.DestroyReasons.NodeDestroy)
|
|
463
|
+
.catch(error => {
|
|
464
|
+
if (enableDebugEvents) {
|
|
465
|
+
console.error(`Node > destroy() Failed to destroy player ${player.guildId}: ${error.message}`);
|
|
466
|
+
}
|
|
467
|
+
})));
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
// Handle all player operations first, then clean up the socket
|
|
471
|
+
handlePlayerOperations().finally(() => {
|
|
472
|
+
this.socket.close(1000, "Node-Destroy");
|
|
473
|
+
this.socket.removeAllListeners();
|
|
474
|
+
this.socket = null;
|
|
475
|
+
this.reconnectAttempts = 1;
|
|
476
|
+
clearTimeout(this.reconnectTimeout);
|
|
477
|
+
if (deleteNode) {
|
|
478
|
+
this.NodeManager.emit("destroy", this, destroyReason);
|
|
479
|
+
this.NodeManager.nodes.delete(this.id);
|
|
480
|
+
clearInterval(this.heartBeatInterval);
|
|
481
|
+
clearTimeout(this.pingTimeout);
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
this.NodeManager.emit("disconnect", this, { code: 1000, reason: destroyReason });
|
|
485
|
+
}
|
|
429
486
|
});
|
|
430
|
-
this.socket.close(1000, "Node-Destroy");
|
|
431
|
-
this.socket.removeAllListeners();
|
|
432
|
-
this.socket = null;
|
|
433
|
-
this.reconnectAttempts = 1;
|
|
434
|
-
clearTimeout(this.reconnectTimeout);
|
|
435
|
-
if (deleteNode) {
|
|
436
|
-
this.NodeManager.emit("destroy", this, destroyReason);
|
|
437
|
-
this.NodeManager.nodes.delete(this.id);
|
|
438
487
|
}
|
|
439
|
-
else {
|
|
440
|
-
this.
|
|
488
|
+
else { // If no players, proceed with socket cleanup immediately
|
|
489
|
+
this.socket.close(1000, "Node-Destroy");
|
|
490
|
+
this.socket.removeAllListeners();
|
|
491
|
+
this.socket = null;
|
|
492
|
+
this.reconnectAttempts = 1;
|
|
493
|
+
clearTimeout(this.reconnectTimeout);
|
|
494
|
+
if (deleteNode) {
|
|
495
|
+
this.NodeManager.emit("destroy", this, destroyReason);
|
|
496
|
+
this.NodeManager.nodes.delete(this.id);
|
|
497
|
+
clearInterval(this.heartBeatInterval);
|
|
498
|
+
clearTimeout(this.pingTimeout);
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
this.NodeManager.emit("disconnect", this, { code: 1000, reason: destroyReason });
|
|
502
|
+
}
|
|
441
503
|
}
|
|
442
504
|
return;
|
|
443
505
|
}
|
|
@@ -966,8 +1028,11 @@ class LavalinkNode {
|
|
|
966
1028
|
if (code === 1000 && reason === "Node-Disconnect")
|
|
967
1029
|
return; // manually disconnected and already emitted the event.
|
|
968
1030
|
this.NodeManager.emit("disconnect", this, { code, reason });
|
|
969
|
-
if (code !== 1000 || reason !== "Node-Destroy")
|
|
970
|
-
this.
|
|
1031
|
+
if (code !== 1000 || reason !== "Node-Destroy") {
|
|
1032
|
+
if (this.NodeManager.nodes.has(this.id)) { // try to reconnect only when the node is still in the nodeManager.nodes list
|
|
1033
|
+
this.reconnect();
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
971
1036
|
}
|
|
972
1037
|
/** @private util function for handling error events from websocket */
|
|
973
1038
|
error(error) {
|
|
@@ -1159,6 +1224,8 @@ class LavalinkNode {
|
|
|
1159
1224
|
}
|
|
1160
1225
|
/** @private util function for handling trackEnd event */
|
|
1161
1226
|
async trackEnd(player, track, payload) {
|
|
1227
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1228
|
+
return; // Check if nodeChange is in Progress than stop the trackEnd Event from being triggered.
|
|
1162
1229
|
const trackToUse = track || this.getTrackOfPayload(payload);
|
|
1163
1230
|
// If a track was forcibly played
|
|
1164
1231
|
if (payload.reason === "replaced") {
|
|
@@ -1374,6 +1441,8 @@ class LavalinkNode {
|
|
|
1374
1441
|
}
|
|
1375
1442
|
/** private util function for handling the queue end event */
|
|
1376
1443
|
async queueEnd(player, track, payload) {
|
|
1444
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1445
|
+
return; // Check if nodeChange is in Progress than stop the queueEnd Event from being triggered.
|
|
1377
1446
|
// add previous track to the queue!
|
|
1378
1447
|
player.queue.current = null;
|
|
1379
1448
|
player.playing = false;
|
|
@@ -83,7 +83,18 @@ export declare class NodeManager extends EventEmitter {
|
|
|
83
83
|
/**
|
|
84
84
|
* Delete a node from the nodeManager and destroy it
|
|
85
85
|
* @param node The node to delete
|
|
86
|
+
* @param movePlayers whether to movePlayers to different connected node before deletion. @default false
|
|
86
87
|
* @returns
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* Deletes the node
|
|
91
|
+
* ```ts
|
|
92
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete");
|
|
93
|
+
* ```
|
|
94
|
+
* Moves players to a different node before deleting
|
|
95
|
+
* ```ts
|
|
96
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete", true);
|
|
97
|
+
* ```
|
|
87
98
|
*/
|
|
88
|
-
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
99
|
+
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode, movePlayers?: boolean): void;
|
|
89
100
|
}
|
|
@@ -196,13 +196,27 @@ class NodeManager extends events_1.EventEmitter {
|
|
|
196
196
|
/**
|
|
197
197
|
* Delete a node from the nodeManager and destroy it
|
|
198
198
|
* @param node The node to delete
|
|
199
|
+
* @param movePlayers whether to movePlayers to different connected node before deletion. @default false
|
|
199
200
|
* @returns
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* Deletes the node
|
|
204
|
+
* ```ts
|
|
205
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete");
|
|
206
|
+
* ```
|
|
207
|
+
* Moves players to a different node before deleting
|
|
208
|
+
* ```ts
|
|
209
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete", true);
|
|
210
|
+
* ```
|
|
200
211
|
*/
|
|
201
|
-
deleteNode(node) {
|
|
212
|
+
deleteNode(node, movePlayers = false) {
|
|
202
213
|
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes()[0];
|
|
203
214
|
if (!decodeNode)
|
|
204
215
|
throw new Error("Node was not found");
|
|
205
|
-
|
|
216
|
+
if (movePlayers)
|
|
217
|
+
decodeNode.destroy(Constants_1.DestroyReasons.NodeDeleted, true, true);
|
|
218
|
+
else
|
|
219
|
+
decodeNode.destroy(Constants_1.DestroyReasons.NodeDeleted);
|
|
206
220
|
this.nodes.delete(decodeNode.id);
|
|
207
221
|
return;
|
|
208
222
|
}
|
|
@@ -217,8 +217,9 @@ export declare class Player {
|
|
|
217
217
|
/**
|
|
218
218
|
* Move the player on a different Audio-Node
|
|
219
219
|
* @param newNode New Node / New Node Id
|
|
220
|
+
* @param checkSources If it should check if the sources are supported by the new node
|
|
220
221
|
*/
|
|
221
|
-
changeNode(newNode: LavalinkNode | string): Promise<string>;
|
|
222
|
+
changeNode(newNode: LavalinkNode | string, checkSources?: boolean): Promise<string>;
|
|
222
223
|
/** Converts the Player including Queue to a Json state */
|
|
223
224
|
toJSON(): PlayerJson;
|
|
224
225
|
}
|
|
@@ -459,11 +459,11 @@ class Player {
|
|
|
459
459
|
throw new RangeError("Can't skip more than the queue size");
|
|
460
460
|
await this.queue.splice(0, skipTo - 1);
|
|
461
461
|
}
|
|
462
|
-
if (!this.playing)
|
|
462
|
+
if (!this.playing && !this.queue.current)
|
|
463
463
|
return (this.play(), this);
|
|
464
464
|
const now = performance.now();
|
|
465
465
|
this.set("internal_skipped", true);
|
|
466
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null } } });
|
|
466
|
+
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null }, paused: false } });
|
|
467
467
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
468
468
|
return this;
|
|
469
469
|
}
|
|
@@ -639,11 +639,37 @@ class Player {
|
|
|
639
639
|
/**
|
|
640
640
|
* Move the player on a different Audio-Node
|
|
641
641
|
* @param newNode New Node / New Node Id
|
|
642
|
+
* @param checkSources If it should check if the sources are supported by the new node
|
|
642
643
|
*/
|
|
643
|
-
async changeNode(newNode) {
|
|
644
|
+
async changeNode(newNode, checkSources = true) {
|
|
644
645
|
const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
|
|
645
646
|
if (!updateNode)
|
|
646
647
|
throw new Error("Could not find the new Node");
|
|
648
|
+
if (!updateNode.connected)
|
|
649
|
+
throw new Error("The provided Node is not active or disconnected");
|
|
650
|
+
if (this.node.id === updateNode.id)
|
|
651
|
+
throw new Error("Player is already on the provided Node");
|
|
652
|
+
if (this.get("internal_nodeChanging") === true)
|
|
653
|
+
throw new Error("Player is already changing the node please wait");
|
|
654
|
+
if (checkSources) {
|
|
655
|
+
const isDefaultSource = () => {
|
|
656
|
+
try {
|
|
657
|
+
this.LavalinkManager.utils.validateSourceString(updateNode, this.LavalinkManager.options.playerOptions.defaultSearchPlatform);
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
660
|
+
catch {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
if (!isDefaultSource())
|
|
665
|
+
throw new RangeError(`defaultSearchPlatform "${this.LavalinkManager.options.playerOptions.defaultSearchPlatform}" is not supported by the newNode`);
|
|
666
|
+
if (this.queue.current || this.queue.tracks.length) { // Check if all queued track sources are supported by the new node
|
|
667
|
+
const trackSources = new Set([this.queue.current, ...this.queue.tracks].map(track => track.info.sourceName));
|
|
668
|
+
const missingSources = [...trackSources].filter(source => !updateNode.info.sourceManagers.includes(source));
|
|
669
|
+
if (missingSources.length)
|
|
670
|
+
throw new RangeError(`Sources missing for Node ${updateNode.id}: ${missingSources.join(', ')}`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
647
673
|
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
648
674
|
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerChangeNode, {
|
|
649
675
|
state: "log",
|
|
@@ -653,23 +679,60 @@ class Player {
|
|
|
653
679
|
}
|
|
654
680
|
const data = this.toJSON();
|
|
655
681
|
const currentTrack = this.queue.current;
|
|
656
|
-
|
|
682
|
+
const voiceData = this.voice;
|
|
683
|
+
if (!voiceData.endpoint ||
|
|
684
|
+
!voiceData.sessionId ||
|
|
685
|
+
!voiceData.token)
|
|
686
|
+
throw new Error("Voice Data is missing, can't change the node");
|
|
687
|
+
this.set("internal_nodeChanging", true); // This will stop execution of trackEnd or queueEnd event while changing the node
|
|
688
|
+
if (this.node.connected)
|
|
689
|
+
await this.node.destroyPlayer(this.guildId); // destroy the player on the currentNode if it's connected
|
|
657
690
|
this.node = updateNode;
|
|
658
691
|
const now = performance.now();
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
692
|
+
try {
|
|
693
|
+
await this.connect();
|
|
694
|
+
const endpoint = `/sessions/${this.node.sessionId}/players/${this.guildId}`; //Send the VoiceData to the newly connected node.
|
|
695
|
+
await this.node.request(endpoint, r => {
|
|
696
|
+
r.method = "PATCH";
|
|
697
|
+
r.headers["Content-Type"] = "application/json";
|
|
698
|
+
r.body = JSON.stringify({
|
|
699
|
+
voice: {
|
|
700
|
+
token: voiceData.token,
|
|
701
|
+
endpoint: voiceData.endpoint,
|
|
702
|
+
sessionId: voiceData.sessionId
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
if (currentTrack) { // If there is a current track, send it to the new node.
|
|
707
|
+
await this.node.updatePlayer({
|
|
708
|
+
guildId: this.guildId,
|
|
709
|
+
noReplace: false,
|
|
710
|
+
playerOptions: {
|
|
711
|
+
track: currentTrack ?? null,
|
|
712
|
+
position: currentTrack ? data.position : 0,
|
|
713
|
+
volume: data.lavalinkVolume,
|
|
714
|
+
paused: data.paused,
|
|
715
|
+
//filters: { ...data.filters, equalizer: data.equalizer }, Sending filters on nodeChange causes issues (player gets dicsonnected)
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
720
|
+
return this.node.id;
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
724
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerChangeNode, {
|
|
725
|
+
state: "error",
|
|
726
|
+
error: error,
|
|
727
|
+
message: `Player.changeNode() execution failed`,
|
|
728
|
+
functionLayer: "Player > changeNode()",
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
throw new Error(`Failed to change the node: ${error}`);
|
|
732
|
+
}
|
|
733
|
+
finally {
|
|
734
|
+
this.set("internal_nodeChanging", undefined);
|
|
735
|
+
}
|
|
673
736
|
}
|
|
674
737
|
/** Converts the Player including Queue to a Json state */
|
|
675
738
|
toJSON() {
|
|
@@ -49,6 +49,8 @@ export declare enum DestroyReasons {
|
|
|
49
49
|
NodeReconnectFail = "NodeReconnectFail",
|
|
50
50
|
Disconnected = "Disconnected",
|
|
51
51
|
PlayerReconnectFail = "PlayerReconnectFail",
|
|
52
|
+
PlayerChangeNodeFail = "PlayerChangeNodeFail",
|
|
53
|
+
PlayerChangeNodeFailNoEligibleNode = "PlayerChangeNodeFailNoEligibleNode",
|
|
52
54
|
ChannelDeleted = "ChannelDeleted",
|
|
53
55
|
DisconnectAllNodes = "DisconnectAllNodes",
|
|
54
56
|
ReconnectAllNodes = "ReconnectAllNodes",
|
|
@@ -50,6 +50,8 @@ export var DestroyReasons;
|
|
|
50
50
|
DestroyReasons["NodeReconnectFail"] = "NodeReconnectFail";
|
|
51
51
|
DestroyReasons["Disconnected"] = "Disconnected";
|
|
52
52
|
DestroyReasons["PlayerReconnectFail"] = "PlayerReconnectFail";
|
|
53
|
+
DestroyReasons["PlayerChangeNodeFail"] = "PlayerChangeNodeFail";
|
|
54
|
+
DestroyReasons["PlayerChangeNodeFailNoEligibleNode"] = "PlayerChangeNodeFailNoEligibleNode";
|
|
53
55
|
DestroyReasons["ChannelDeleted"] = "ChannelDeleted";
|
|
54
56
|
DestroyReasons["DisconnectAllNodes"] = "DisconnectAllNodes";
|
|
55
57
|
DestroyReasons["ReconnectAllNodes"] = "ReconnectAllNodes";
|
|
@@ -173,14 +173,20 @@ export declare class LavalinkNode {
|
|
|
173
173
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
174
174
|
* @param destroyReason Destroy Reason to use when destroying the players
|
|
175
175
|
* @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
|
|
176
|
+
* @param movePlayers whether to movePlayers to different eligible connected node. If false players won't be moved @default false
|
|
176
177
|
* @returns void
|
|
177
178
|
*
|
|
178
179
|
* @example
|
|
180
|
+
* Destroys node and its players
|
|
179
181
|
* ```ts
|
|
180
182
|
* player.node.destroy("custom Player Destroy Reason", true);
|
|
181
183
|
* ```
|
|
184
|
+
* destroys only the node and moves its players to different connected node.
|
|
185
|
+
* ```ts
|
|
186
|
+
* player.node.destroy("custom Player Destroy Reason", true, true);
|
|
187
|
+
* ```
|
|
182
188
|
*/
|
|
183
|
-
destroy(destroyReason?: DestroyReasonsType, deleteNode?: boolean): void;
|
|
189
|
+
destroy(destroyReason?: DestroyReasonsType, deleteNode?: boolean, movePlayers?: boolean): void;
|
|
184
190
|
/**
|
|
185
191
|
* Disconnects the Node-Connection (Websocket)
|
|
186
192
|
* @param disconnectReason Disconnect Reason to use when disconnecting Node
|
|
@@ -408,32 +408,94 @@ export class LavalinkNode {
|
|
|
408
408
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
409
409
|
* @param destroyReason Destroy Reason to use when destroying the players
|
|
410
410
|
* @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
|
|
411
|
+
* @param movePlayers whether to movePlayers to different eligible connected node. If false players won't be moved @default false
|
|
411
412
|
* @returns void
|
|
412
413
|
*
|
|
413
414
|
* @example
|
|
415
|
+
* Destroys node and its players
|
|
414
416
|
* ```ts
|
|
415
417
|
* player.node.destroy("custom Player Destroy Reason", true);
|
|
416
418
|
* ```
|
|
419
|
+
* destroys only the node and moves its players to different connected node.
|
|
420
|
+
* ```ts
|
|
421
|
+
* player.node.destroy("custom Player Destroy Reason", true, true);
|
|
422
|
+
* ```
|
|
417
423
|
*/
|
|
418
|
-
destroy(destroyReason, deleteNode = true) {
|
|
424
|
+
destroy(destroyReason, deleteNode = true, movePlayers = false) {
|
|
419
425
|
if (!this.connected)
|
|
420
426
|
return;
|
|
421
427
|
const players = this.NodeManager.LavalinkManager.players.filter(p => p.node.id === this.id);
|
|
422
|
-
if (players)
|
|
423
|
-
|
|
424
|
-
|
|
428
|
+
if (players.size) {
|
|
429
|
+
const enableDebugEvents = this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents;
|
|
430
|
+
const handlePlayerOperations = () => {
|
|
431
|
+
if (movePlayers) {
|
|
432
|
+
const nodeToMove = Array.from(this.NodeManager.leastUsedNodes("playingPlayers"))
|
|
433
|
+
.find(n => n.connected && n.options.id !== this.id);
|
|
434
|
+
if (nodeToMove) {
|
|
435
|
+
return Promise.allSettled(Array.from(players.values()).map(player => player.changeNode(nodeToMove.options.id)
|
|
436
|
+
.catch(error => {
|
|
437
|
+
if (enableDebugEvents) {
|
|
438
|
+
console.error(`Node > destroy() Failed to move player ${player.guildId}: ${error.message}`);
|
|
439
|
+
}
|
|
440
|
+
return player.destroy(error.message ?? DestroyReasons.PlayerChangeNodeFail)
|
|
441
|
+
.catch(destroyError => {
|
|
442
|
+
if (enableDebugEvents) {
|
|
443
|
+
console.error(`Node > destroy() Failed to destroy player ${player.guildId} after move failure: ${destroyError.message}`);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
})));
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
return Promise.allSettled(Array.from(players.values()).map(player => player.destroy(DestroyReasons.PlayerChangeNodeFailNoEligibleNode)
|
|
450
|
+
.catch(error => {
|
|
451
|
+
if (enableDebugEvents) {
|
|
452
|
+
console.error(`Node > destroy() Failed to destroy player ${player.guildId}: ${error.message}`);
|
|
453
|
+
}
|
|
454
|
+
})));
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
return Promise.allSettled(Array.from(players.values()).map(player => player.destroy(destroyReason || DestroyReasons.NodeDestroy)
|
|
459
|
+
.catch(error => {
|
|
460
|
+
if (enableDebugEvents) {
|
|
461
|
+
console.error(`Node > destroy() Failed to destroy player ${player.guildId}: ${error.message}`);
|
|
462
|
+
}
|
|
463
|
+
})));
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
// Handle all player operations first, then clean up the socket
|
|
467
|
+
handlePlayerOperations().finally(() => {
|
|
468
|
+
this.socket.close(1000, "Node-Destroy");
|
|
469
|
+
this.socket.removeAllListeners();
|
|
470
|
+
this.socket = null;
|
|
471
|
+
this.reconnectAttempts = 1;
|
|
472
|
+
clearTimeout(this.reconnectTimeout);
|
|
473
|
+
if (deleteNode) {
|
|
474
|
+
this.NodeManager.emit("destroy", this, destroyReason);
|
|
475
|
+
this.NodeManager.nodes.delete(this.id);
|
|
476
|
+
clearInterval(this.heartBeatInterval);
|
|
477
|
+
clearTimeout(this.pingTimeout);
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
this.NodeManager.emit("disconnect", this, { code: 1000, reason: destroyReason });
|
|
481
|
+
}
|
|
425
482
|
});
|
|
426
|
-
this.socket.close(1000, "Node-Destroy");
|
|
427
|
-
this.socket.removeAllListeners();
|
|
428
|
-
this.socket = null;
|
|
429
|
-
this.reconnectAttempts = 1;
|
|
430
|
-
clearTimeout(this.reconnectTimeout);
|
|
431
|
-
if (deleteNode) {
|
|
432
|
-
this.NodeManager.emit("destroy", this, destroyReason);
|
|
433
|
-
this.NodeManager.nodes.delete(this.id);
|
|
434
483
|
}
|
|
435
|
-
else {
|
|
436
|
-
this.
|
|
484
|
+
else { // If no players, proceed with socket cleanup immediately
|
|
485
|
+
this.socket.close(1000, "Node-Destroy");
|
|
486
|
+
this.socket.removeAllListeners();
|
|
487
|
+
this.socket = null;
|
|
488
|
+
this.reconnectAttempts = 1;
|
|
489
|
+
clearTimeout(this.reconnectTimeout);
|
|
490
|
+
if (deleteNode) {
|
|
491
|
+
this.NodeManager.emit("destroy", this, destroyReason);
|
|
492
|
+
this.NodeManager.nodes.delete(this.id);
|
|
493
|
+
clearInterval(this.heartBeatInterval);
|
|
494
|
+
clearTimeout(this.pingTimeout);
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
this.NodeManager.emit("disconnect", this, { code: 1000, reason: destroyReason });
|
|
498
|
+
}
|
|
437
499
|
}
|
|
438
500
|
return;
|
|
439
501
|
}
|
|
@@ -962,8 +1024,11 @@ export class LavalinkNode {
|
|
|
962
1024
|
if (code === 1000 && reason === "Node-Disconnect")
|
|
963
1025
|
return; // manually disconnected and already emitted the event.
|
|
964
1026
|
this.NodeManager.emit("disconnect", this, { code, reason });
|
|
965
|
-
if (code !== 1000 || reason !== "Node-Destroy")
|
|
966
|
-
this.
|
|
1027
|
+
if (code !== 1000 || reason !== "Node-Destroy") {
|
|
1028
|
+
if (this.NodeManager.nodes.has(this.id)) { // try to reconnect only when the node is still in the nodeManager.nodes list
|
|
1029
|
+
this.reconnect();
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
967
1032
|
}
|
|
968
1033
|
/** @private util function for handling error events from websocket */
|
|
969
1034
|
error(error) {
|
|
@@ -1155,6 +1220,8 @@ export class LavalinkNode {
|
|
|
1155
1220
|
}
|
|
1156
1221
|
/** @private util function for handling trackEnd event */
|
|
1157
1222
|
async trackEnd(player, track, payload) {
|
|
1223
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1224
|
+
return; // Check if nodeChange is in Progress than stop the trackEnd Event from being triggered.
|
|
1158
1225
|
const trackToUse = track || this.getTrackOfPayload(payload);
|
|
1159
1226
|
// If a track was forcibly played
|
|
1160
1227
|
if (payload.reason === "replaced") {
|
|
@@ -1370,6 +1437,8 @@ export class LavalinkNode {
|
|
|
1370
1437
|
}
|
|
1371
1438
|
/** private util function for handling the queue end event */
|
|
1372
1439
|
async queueEnd(player, track, payload) {
|
|
1440
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1441
|
+
return; // Check if nodeChange is in Progress than stop the queueEnd Event from being triggered.
|
|
1373
1442
|
// add previous track to the queue!
|
|
1374
1443
|
player.queue.current = null;
|
|
1375
1444
|
player.playing = false;
|
|
@@ -83,7 +83,18 @@ export declare class NodeManager extends EventEmitter {
|
|
|
83
83
|
/**
|
|
84
84
|
* Delete a node from the nodeManager and destroy it
|
|
85
85
|
* @param node The node to delete
|
|
86
|
+
* @param movePlayers whether to movePlayers to different connected node before deletion. @default false
|
|
86
87
|
* @returns
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* Deletes the node
|
|
91
|
+
* ```ts
|
|
92
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete");
|
|
93
|
+
* ```
|
|
94
|
+
* Moves players to a different node before deleting
|
|
95
|
+
* ```ts
|
|
96
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete", true);
|
|
97
|
+
* ```
|
|
87
98
|
*/
|
|
88
|
-
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
99
|
+
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode, movePlayers?: boolean): void;
|
|
89
100
|
}
|
|
@@ -193,13 +193,27 @@ export class NodeManager extends EventEmitter {
|
|
|
193
193
|
/**
|
|
194
194
|
* Delete a node from the nodeManager and destroy it
|
|
195
195
|
* @param node The node to delete
|
|
196
|
+
* @param movePlayers whether to movePlayers to different connected node before deletion. @default false
|
|
196
197
|
* @returns
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* Deletes the node
|
|
201
|
+
* ```ts
|
|
202
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete");
|
|
203
|
+
* ```
|
|
204
|
+
* Moves players to a different node before deleting
|
|
205
|
+
* ```ts
|
|
206
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete", true);
|
|
207
|
+
* ```
|
|
197
208
|
*/
|
|
198
|
-
deleteNode(node) {
|
|
209
|
+
deleteNode(node, movePlayers = false) {
|
|
199
210
|
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes()[0];
|
|
200
211
|
if (!decodeNode)
|
|
201
212
|
throw new Error("Node was not found");
|
|
202
|
-
|
|
213
|
+
if (movePlayers)
|
|
214
|
+
decodeNode.destroy(DestroyReasons.NodeDeleted, true, true);
|
|
215
|
+
else
|
|
216
|
+
decodeNode.destroy(DestroyReasons.NodeDeleted);
|
|
203
217
|
this.nodes.delete(decodeNode.id);
|
|
204
218
|
return;
|
|
205
219
|
}
|
|
@@ -217,8 +217,9 @@ export declare class Player {
|
|
|
217
217
|
/**
|
|
218
218
|
* Move the player on a different Audio-Node
|
|
219
219
|
* @param newNode New Node / New Node Id
|
|
220
|
+
* @param checkSources If it should check if the sources are supported by the new node
|
|
220
221
|
*/
|
|
221
|
-
changeNode(newNode: LavalinkNode | string): Promise<string>;
|
|
222
|
+
changeNode(newNode: LavalinkNode | string, checkSources?: boolean): Promise<string>;
|
|
222
223
|
/** Converts the Player including Queue to a Json state */
|
|
223
224
|
toJSON(): PlayerJson;
|
|
224
225
|
}
|
|
@@ -456,11 +456,11 @@ export class Player {
|
|
|
456
456
|
throw new RangeError("Can't skip more than the queue size");
|
|
457
457
|
await this.queue.splice(0, skipTo - 1);
|
|
458
458
|
}
|
|
459
|
-
if (!this.playing)
|
|
459
|
+
if (!this.playing && !this.queue.current)
|
|
460
460
|
return (this.play(), this);
|
|
461
461
|
const now = performance.now();
|
|
462
462
|
this.set("internal_skipped", true);
|
|
463
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null } } });
|
|
463
|
+
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null }, paused: false } });
|
|
464
464
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
465
465
|
return this;
|
|
466
466
|
}
|
|
@@ -636,11 +636,37 @@ export class Player {
|
|
|
636
636
|
/**
|
|
637
637
|
* Move the player on a different Audio-Node
|
|
638
638
|
* @param newNode New Node / New Node Id
|
|
639
|
+
* @param checkSources If it should check if the sources are supported by the new node
|
|
639
640
|
*/
|
|
640
|
-
async changeNode(newNode) {
|
|
641
|
+
async changeNode(newNode, checkSources = true) {
|
|
641
642
|
const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
|
|
642
643
|
if (!updateNode)
|
|
643
644
|
throw new Error("Could not find the new Node");
|
|
645
|
+
if (!updateNode.connected)
|
|
646
|
+
throw new Error("The provided Node is not active or disconnected");
|
|
647
|
+
if (this.node.id === updateNode.id)
|
|
648
|
+
throw new Error("Player is already on the provided Node");
|
|
649
|
+
if (this.get("internal_nodeChanging") === true)
|
|
650
|
+
throw new Error("Player is already changing the node please wait");
|
|
651
|
+
if (checkSources) {
|
|
652
|
+
const isDefaultSource = () => {
|
|
653
|
+
try {
|
|
654
|
+
this.LavalinkManager.utils.validateSourceString(updateNode, this.LavalinkManager.options.playerOptions.defaultSearchPlatform);
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
catch {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
if (!isDefaultSource())
|
|
662
|
+
throw new RangeError(`defaultSearchPlatform "${this.LavalinkManager.options.playerOptions.defaultSearchPlatform}" is not supported by the newNode`);
|
|
663
|
+
if (this.queue.current || this.queue.tracks.length) { // Check if all queued track sources are supported by the new node
|
|
664
|
+
const trackSources = new Set([this.queue.current, ...this.queue.tracks].map(track => track.info.sourceName));
|
|
665
|
+
const missingSources = [...trackSources].filter(source => !updateNode.info.sourceManagers.includes(source));
|
|
666
|
+
if (missingSources.length)
|
|
667
|
+
throw new RangeError(`Sources missing for Node ${updateNode.id}: ${missingSources.join(', ')}`);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
644
670
|
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
645
671
|
this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
|
|
646
672
|
state: "log",
|
|
@@ -650,23 +676,60 @@ export class Player {
|
|
|
650
676
|
}
|
|
651
677
|
const data = this.toJSON();
|
|
652
678
|
const currentTrack = this.queue.current;
|
|
653
|
-
|
|
679
|
+
const voiceData = this.voice;
|
|
680
|
+
if (!voiceData.endpoint ||
|
|
681
|
+
!voiceData.sessionId ||
|
|
682
|
+
!voiceData.token)
|
|
683
|
+
throw new Error("Voice Data is missing, can't change the node");
|
|
684
|
+
this.set("internal_nodeChanging", true); // This will stop execution of trackEnd or queueEnd event while changing the node
|
|
685
|
+
if (this.node.connected)
|
|
686
|
+
await this.node.destroyPlayer(this.guildId); // destroy the player on the currentNode if it's connected
|
|
654
687
|
this.node = updateNode;
|
|
655
688
|
const now = performance.now();
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
689
|
+
try {
|
|
690
|
+
await this.connect();
|
|
691
|
+
const endpoint = `/sessions/${this.node.sessionId}/players/${this.guildId}`; //Send the VoiceData to the newly connected node.
|
|
692
|
+
await this.node.request(endpoint, r => {
|
|
693
|
+
r.method = "PATCH";
|
|
694
|
+
r.headers["Content-Type"] = "application/json";
|
|
695
|
+
r.body = JSON.stringify({
|
|
696
|
+
voice: {
|
|
697
|
+
token: voiceData.token,
|
|
698
|
+
endpoint: voiceData.endpoint,
|
|
699
|
+
sessionId: voiceData.sessionId
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
});
|
|
703
|
+
if (currentTrack) { // If there is a current track, send it to the new node.
|
|
704
|
+
await this.node.updatePlayer({
|
|
705
|
+
guildId: this.guildId,
|
|
706
|
+
noReplace: false,
|
|
707
|
+
playerOptions: {
|
|
708
|
+
track: currentTrack ?? null,
|
|
709
|
+
position: currentTrack ? data.position : 0,
|
|
710
|
+
volume: data.lavalinkVolume,
|
|
711
|
+
paused: data.paused,
|
|
712
|
+
//filters: { ...data.filters, equalizer: data.equalizer }, Sending filters on nodeChange causes issues (player gets dicsonnected)
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
717
|
+
return this.node.id;
|
|
718
|
+
}
|
|
719
|
+
catch (error) {
|
|
720
|
+
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
721
|
+
this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
|
|
722
|
+
state: "error",
|
|
723
|
+
error: error,
|
|
724
|
+
message: `Player.changeNode() execution failed`,
|
|
725
|
+
functionLayer: "Player > changeNode()",
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
throw new Error(`Failed to change the node: ${error}`);
|
|
729
|
+
}
|
|
730
|
+
finally {
|
|
731
|
+
this.set("internal_nodeChanging", undefined);
|
|
732
|
+
}
|
|
670
733
|
}
|
|
671
734
|
/** Converts the Player including Queue to a Json state */
|
|
672
735
|
toJSON() {
|
|
@@ -49,6 +49,8 @@ export declare enum DestroyReasons {
|
|
|
49
49
|
NodeReconnectFail = "NodeReconnectFail",
|
|
50
50
|
Disconnected = "Disconnected",
|
|
51
51
|
PlayerReconnectFail = "PlayerReconnectFail",
|
|
52
|
+
PlayerChangeNodeFail = "PlayerChangeNodeFail",
|
|
53
|
+
PlayerChangeNodeFailNoEligibleNode = "PlayerChangeNodeFailNoEligibleNode",
|
|
52
54
|
ChannelDeleted = "ChannelDeleted",
|
|
53
55
|
DisconnectAllNodes = "DisconnectAllNodes",
|
|
54
56
|
ReconnectAllNodes = "ReconnectAllNodes",
|
|
@@ -173,14 +173,20 @@ export declare class LavalinkNode {
|
|
|
173
173
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
174
174
|
* @param destroyReason Destroy Reason to use when destroying the players
|
|
175
175
|
* @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
|
|
176
|
+
* @param movePlayers whether to movePlayers to different eligible connected node. If false players won't be moved @default false
|
|
176
177
|
* @returns void
|
|
177
178
|
*
|
|
178
179
|
* @example
|
|
180
|
+
* Destroys node and its players
|
|
179
181
|
* ```ts
|
|
180
182
|
* player.node.destroy("custom Player Destroy Reason", true);
|
|
181
183
|
* ```
|
|
184
|
+
* destroys only the node and moves its players to different connected node.
|
|
185
|
+
* ```ts
|
|
186
|
+
* player.node.destroy("custom Player Destroy Reason", true, true);
|
|
187
|
+
* ```
|
|
182
188
|
*/
|
|
183
|
-
destroy(destroyReason?: DestroyReasonsType, deleteNode?: boolean): void;
|
|
189
|
+
destroy(destroyReason?: DestroyReasonsType, deleteNode?: boolean, movePlayers?: boolean): void;
|
|
184
190
|
/**
|
|
185
191
|
* Disconnects the Node-Connection (Websocket)
|
|
186
192
|
* @param disconnectReason Disconnect Reason to use when disconnecting Node
|
|
@@ -83,7 +83,18 @@ export declare class NodeManager extends EventEmitter {
|
|
|
83
83
|
/**
|
|
84
84
|
* Delete a node from the nodeManager and destroy it
|
|
85
85
|
* @param node The node to delete
|
|
86
|
+
* @param movePlayers whether to movePlayers to different connected node before deletion. @default false
|
|
86
87
|
* @returns
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* Deletes the node
|
|
91
|
+
* ```ts
|
|
92
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete");
|
|
93
|
+
* ```
|
|
94
|
+
* Moves players to a different node before deleting
|
|
95
|
+
* ```ts
|
|
96
|
+
* client.lavalink.nodeManager.deleteNode("nodeId to delete", true);
|
|
97
|
+
* ```
|
|
87
98
|
*/
|
|
88
|
-
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
99
|
+
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode, movePlayers?: boolean): void;
|
|
89
100
|
}
|
|
@@ -217,8 +217,9 @@ export declare class Player {
|
|
|
217
217
|
/**
|
|
218
218
|
* Move the player on a different Audio-Node
|
|
219
219
|
* @param newNode New Node / New Node Id
|
|
220
|
+
* @param checkSources If it should check if the sources are supported by the new node
|
|
220
221
|
*/
|
|
221
|
-
changeNode(newNode: LavalinkNode | string): Promise<string>;
|
|
222
|
+
changeNode(newNode: LavalinkNode | string, checkSources?: boolean): Promise<string>;
|
|
222
223
|
/** Converts the Player including Queue to a Json state */
|
|
223
224
|
toJSON(): PlayerJson;
|
|
224
225
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lavalink-client",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.6",
|
|
4
4
|
"description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -58,22 +58,22 @@
|
|
|
58
58
|
},
|
|
59
59
|
"homepage": "https://tomato6966.github.io/lavalink-client/",
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@eslint/eslintrc": "^3.
|
|
62
|
-
"@eslint/js": "^9.
|
|
63
|
-
"@types/node": "^22.
|
|
64
|
-
"@types/ws": "^8.5.
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
66
|
-
"@typescript-eslint/parser": "^8.
|
|
67
|
-
"eslint": "^9.
|
|
61
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
62
|
+
"@eslint/js": "^9.18.0",
|
|
63
|
+
"@types/node": "^22.10.5",
|
|
64
|
+
"@types/ws": "^8.5.13",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
|
66
|
+
"@typescript-eslint/parser": "^8.20.0",
|
|
67
|
+
"eslint": "^9.18.0",
|
|
68
68
|
"tsc-alias": "^1.8.10",
|
|
69
|
-
"typescript": "^5.
|
|
69
|
+
"typescript": "^5.7.3"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"tslib": "^2.
|
|
72
|
+
"tslib": "^2.8.1",
|
|
73
73
|
"ws": "^8.18.0"
|
|
74
74
|
},
|
|
75
75
|
"engines": {
|
|
76
76
|
"node": ">=18.0.0",
|
|
77
|
-
"bun": ">=1.
|
|
77
|
+
"bun": ">=1.1.27"
|
|
78
78
|
}
|
|
79
79
|
}
|