lavalink-client 2.4.4 → 2.4.5
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/dist/cjs/structures/Node.js +4 -0
- package/dist/cjs/structures/Player.d.ts +2 -1
- package/dist/cjs/structures/Player.js +81 -18
- package/dist/esm/structures/Node.js +4 -0
- package/dist/esm/structures/Player.d.ts +2 -1
- package/dist/esm/structures/Player.js +81 -18
- package/dist/types/structures/Player.d.ts +2 -1
- package/package.json +11 -11
|
@@ -1159,6 +1159,8 @@ class LavalinkNode {
|
|
|
1159
1159
|
}
|
|
1160
1160
|
/** @private util function for handling trackEnd event */
|
|
1161
1161
|
async trackEnd(player, track, payload) {
|
|
1162
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1163
|
+
return; // Check if nodeChange is in Progress than stop the trackEnd Event from being triggered.
|
|
1162
1164
|
const trackToUse = track || this.getTrackOfPayload(payload);
|
|
1163
1165
|
// If a track was forcibly played
|
|
1164
1166
|
if (payload.reason === "replaced") {
|
|
@@ -1374,6 +1376,8 @@ class LavalinkNode {
|
|
|
1374
1376
|
}
|
|
1375
1377
|
/** private util function for handling the queue end event */
|
|
1376
1378
|
async queueEnd(player, track, payload) {
|
|
1379
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1380
|
+
return; // Check if nodeChange is in Progress than stop the queueEnd Event from being triggered.
|
|
1377
1381
|
// add previous track to the queue!
|
|
1378
1382
|
player.queue.current = null;
|
|
1379
1383
|
player.playing = false;
|
|
@@ -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() {
|
|
@@ -1155,6 +1155,8 @@ export class LavalinkNode {
|
|
|
1155
1155
|
}
|
|
1156
1156
|
/** @private util function for handling trackEnd event */
|
|
1157
1157
|
async trackEnd(player, track, payload) {
|
|
1158
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1159
|
+
return; // Check if nodeChange is in Progress than stop the trackEnd Event from being triggered.
|
|
1158
1160
|
const trackToUse = track || this.getTrackOfPayload(payload);
|
|
1159
1161
|
// If a track was forcibly played
|
|
1160
1162
|
if (payload.reason === "replaced") {
|
|
@@ -1370,6 +1372,8 @@ export class LavalinkNode {
|
|
|
1370
1372
|
}
|
|
1371
1373
|
/** private util function for handling the queue end event */
|
|
1372
1374
|
async queueEnd(player, track, payload) {
|
|
1375
|
+
if (player.get('internal_nodeChanging') === true)
|
|
1376
|
+
return; // Check if nodeChange is in Progress than stop the queueEnd Event from being triggered.
|
|
1373
1377
|
// add previous track to the queue!
|
|
1374
1378
|
player.queue.current = null;
|
|
1375
1379
|
player.playing = false;
|
|
@@ -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() {
|
|
@@ -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.5",
|
|
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
|
}
|