magmastream 2.9.2-dev.1 → 2.9.2-dev.10
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/index.d.ts +103 -23
- package/dist/index.js +1 -0
- package/dist/statestorage/JsonQueue.js +332 -176
- package/dist/statestorage/MemoryQueue.js +288 -203
- package/dist/statestorage/RedisQueue.js +482 -204
- package/dist/structures/Enums.js +110 -1
- package/dist/structures/Filters.js +27 -13
- package/dist/structures/MagmastreamError.js +19 -0
- package/dist/structures/Manager.js +351 -219
- package/dist/structures/Node.js +227 -66
- package/dist/structures/Player.js +199 -58
- package/dist/structures/Rest.js +23 -12
- package/dist/structures/Utils.js +83 -67
- package/dist/utils/managerCheck.js +99 -21
- package/dist/utils/nodeCheck.js +59 -34
- package/dist/utils/playerCheck.js +47 -28
- package/package.json +3 -2
|
@@ -11,6 +11,7 @@ const RedisQueue_1 = require("../statestorage/RedisQueue");
|
|
|
11
11
|
const Enums_1 = require("./Enums");
|
|
12
12
|
const ws_1 = require("ws");
|
|
13
13
|
const JsonQueue_1 = require("../statestorage/JsonQueue");
|
|
14
|
+
const MagmastreamError_1 = require("./MagmastreamError");
|
|
14
15
|
class Player {
|
|
15
16
|
options;
|
|
16
17
|
/** The Queue for the Player. */
|
|
@@ -75,8 +76,12 @@ class Player {
|
|
|
75
76
|
// If the Manager is not initiated, throw an error.
|
|
76
77
|
if (!this.manager)
|
|
77
78
|
this.manager = Utils_1.Structure.get("Player")._manager;
|
|
78
|
-
if (!this.manager)
|
|
79
|
-
throw new
|
|
79
|
+
if (!this.manager) {
|
|
80
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
81
|
+
code: Enums_1.MagmaStreamErrorCode.GENERAL_INVALID_MANAGER,
|
|
82
|
+
message: "Manager instance is required.",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
80
85
|
this.clusterId = this.manager.options.clusterId || 0;
|
|
81
86
|
// Check the player options for errors.
|
|
82
87
|
(0, playerCheck_1.default)(options);
|
|
@@ -102,8 +107,13 @@ class Player {
|
|
|
102
107
|
const node = this.manager.nodes.get(options.nodeIdentifier);
|
|
103
108
|
this.node = node || this.manager.useableNode;
|
|
104
109
|
// If no node is available, throw an error.
|
|
105
|
-
if (!this.node)
|
|
106
|
-
throw new
|
|
110
|
+
if (!this.node) {
|
|
111
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
112
|
+
code: Enums_1.MagmaStreamErrorCode.MANAGER_NO_NODES,
|
|
113
|
+
message: "No available nodes for the player found.",
|
|
114
|
+
context: { guildId: this.guildId },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
107
117
|
// Initialize the queue with the guild ID and manager.
|
|
108
118
|
switch (this.manager.options.stateStorage.type) {
|
|
109
119
|
case Enums_1.StateStorageType.Redis:
|
|
@@ -169,7 +179,11 @@ class Player {
|
|
|
169
179
|
connect() {
|
|
170
180
|
// Check if the voice channel has been set.
|
|
171
181
|
if (!this.voiceChannelId) {
|
|
172
|
-
throw new
|
|
182
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
183
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
|
|
184
|
+
message: "No voice channel has been set. You must set the voice channel before connecting.",
|
|
185
|
+
context: { voiceChannelId: this.voiceChannelId },
|
|
186
|
+
});
|
|
173
187
|
}
|
|
174
188
|
// Set the player state to connecting.
|
|
175
189
|
this.state = Enums_1.StateTypes.Connecting;
|
|
@@ -268,8 +282,12 @@ class Player {
|
|
|
268
282
|
*/
|
|
269
283
|
setVoiceChannelId(channel) {
|
|
270
284
|
// Validate the channel parameter
|
|
271
|
-
if (typeof channel !== "string")
|
|
272
|
-
throw new
|
|
285
|
+
if (typeof channel !== "string") {
|
|
286
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
287
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
|
|
288
|
+
message: "Channel must be a non-empty string.",
|
|
289
|
+
});
|
|
290
|
+
}
|
|
273
291
|
// Clone the current player state for comparison
|
|
274
292
|
const oldPlayer = this ? { ...this } : null;
|
|
275
293
|
// Update the player voice channel
|
|
@@ -300,8 +318,12 @@ class Player {
|
|
|
300
318
|
*/
|
|
301
319
|
setTextChannelId(channel) {
|
|
302
320
|
// Validate the channel parameter
|
|
303
|
-
if (typeof channel !== "string")
|
|
304
|
-
throw new
|
|
321
|
+
if (typeof channel !== "string") {
|
|
322
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
323
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
|
|
324
|
+
message: "Channel must be a non-empty string.",
|
|
325
|
+
});
|
|
326
|
+
}
|
|
305
327
|
// Clone the current player state for comparison
|
|
306
328
|
const oldPlayer = this ? { ...this } : null;
|
|
307
329
|
// Update the text channel property
|
|
@@ -328,8 +350,12 @@ class Player {
|
|
|
328
350
|
*/
|
|
329
351
|
setNowPlayingMessage(message) {
|
|
330
352
|
if (!message) {
|
|
331
|
-
throw new
|
|
353
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
354
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_NOW_PLAYING_MESSAGE,
|
|
355
|
+
message: "You must provide the message of the now playing message.",
|
|
356
|
+
});
|
|
332
357
|
}
|
|
358
|
+
this.set("nowPlayingMessage", message);
|
|
333
359
|
this.nowPlayingMessage = message;
|
|
334
360
|
return this.nowPlayingMessage;
|
|
335
361
|
}
|
|
@@ -337,8 +363,14 @@ class Player {
|
|
|
337
363
|
if (typeof optionsOrTrack !== "undefined" && Utils_1.TrackUtils.validate(optionsOrTrack)) {
|
|
338
364
|
await this.queue.setCurrent(optionsOrTrack);
|
|
339
365
|
}
|
|
340
|
-
if (!(await this.queue.getCurrent()))
|
|
341
|
-
|
|
366
|
+
if (!(await this.queue.getCurrent())) {
|
|
367
|
+
const error = new MagmastreamError_1.MagmaStreamError({
|
|
368
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_QUEUE_EMPTY,
|
|
369
|
+
message: "The queue is empty.",
|
|
370
|
+
});
|
|
371
|
+
console.error(error);
|
|
372
|
+
return this;
|
|
373
|
+
}
|
|
342
374
|
const finalOptions = playOptions
|
|
343
375
|
? playOptions
|
|
344
376
|
: ["startTime", "endTime", "noReplace"].every((v) => Object.keys(optionsOrTrack || {}).includes(v))
|
|
@@ -369,11 +401,21 @@ class Player {
|
|
|
369
401
|
*/
|
|
370
402
|
setAutoplay(autoplayState, AutoplayUser, tries) {
|
|
371
403
|
if (typeof autoplayState !== "boolean") {
|
|
372
|
-
|
|
404
|
+
const error = new MagmastreamError_1.MagmaStreamError({
|
|
405
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_AUTOPLAY,
|
|
406
|
+
message: "autoplayState must be a boolean.",
|
|
407
|
+
});
|
|
408
|
+
console.error(error);
|
|
409
|
+
return this;
|
|
373
410
|
}
|
|
374
411
|
if (autoplayState) {
|
|
375
412
|
if (!AutoplayUser) {
|
|
376
|
-
|
|
413
|
+
const error = new MagmastreamError_1.MagmaStreamError({
|
|
414
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_AUTOPLAY,
|
|
415
|
+
message: "AutoplayUser must be provided when enabling autoplay.",
|
|
416
|
+
});
|
|
417
|
+
console.error(error);
|
|
418
|
+
return this;
|
|
377
419
|
}
|
|
378
420
|
this.autoplayTries = tries && typeof tries === "number" && tries > 0 ? tries : 3; // Default to 3 if invalid
|
|
379
421
|
this.isAutoplay = true;
|
|
@@ -416,16 +458,26 @@ class Player {
|
|
|
416
458
|
* player.setVolume(50);
|
|
417
459
|
*/
|
|
418
460
|
async setVolume(volume) {
|
|
419
|
-
if (isNaN(volume))
|
|
420
|
-
throw new
|
|
461
|
+
if (isNaN(volume)) {
|
|
462
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
463
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_VOLUME,
|
|
464
|
+
message: "Volume must be a number.",
|
|
465
|
+
});
|
|
466
|
+
}
|
|
421
467
|
if (this.options.applyVolumeAsFilter) {
|
|
422
468
|
if (volume < 0 || volume > 500) {
|
|
423
|
-
throw new
|
|
469
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
470
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_VOLUME,
|
|
471
|
+
message: "Volume must be between 0 and 500 when using filter mode (100 = 100%).",
|
|
472
|
+
});
|
|
424
473
|
}
|
|
425
474
|
}
|
|
426
475
|
else {
|
|
427
476
|
if (volume < 0 || volume > 1000) {
|
|
428
|
-
throw new
|
|
477
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
478
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_VOLUME,
|
|
479
|
+
message: "Volume must be between 0 and 1000.",
|
|
480
|
+
});
|
|
429
481
|
}
|
|
430
482
|
}
|
|
431
483
|
const oldVolume = this.volume;
|
|
@@ -481,8 +533,12 @@ class Player {
|
|
|
481
533
|
*/
|
|
482
534
|
setTrackRepeat(repeat) {
|
|
483
535
|
// Ensure the repeat parameter is a boolean
|
|
484
|
-
if (typeof repeat !== "boolean")
|
|
485
|
-
throw new
|
|
536
|
+
if (typeof repeat !== "boolean") {
|
|
537
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
538
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_REPEAT,
|
|
539
|
+
message: "Repeat must be a boolean.",
|
|
540
|
+
});
|
|
541
|
+
}
|
|
486
542
|
// Clone the current player state for event emission
|
|
487
543
|
const oldPlayer = this ? { ...this } : null;
|
|
488
544
|
if (repeat) {
|
|
@@ -517,8 +573,12 @@ class Player {
|
|
|
517
573
|
*/
|
|
518
574
|
setQueueRepeat(repeat) {
|
|
519
575
|
// Ensure the repeat parameter is a boolean
|
|
520
|
-
if (typeof repeat !== "boolean")
|
|
521
|
-
throw new
|
|
576
|
+
if (typeof repeat !== "boolean") {
|
|
577
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
578
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_REPEAT,
|
|
579
|
+
message: "Repeat must be a boolean.",
|
|
580
|
+
});
|
|
581
|
+
}
|
|
522
582
|
// Get the current player state
|
|
523
583
|
const oldPlayer = this ? { ...this } : null;
|
|
524
584
|
// Update the player state
|
|
@@ -555,11 +615,17 @@ class Player {
|
|
|
555
615
|
async setDynamicRepeat(repeat, ms) {
|
|
556
616
|
// Validate the repeat parameter
|
|
557
617
|
if (typeof repeat !== "boolean") {
|
|
558
|
-
throw new
|
|
618
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
619
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_REPEAT,
|
|
620
|
+
message: "Repeat must be a boolean.",
|
|
621
|
+
});
|
|
559
622
|
}
|
|
560
623
|
// Ensure the queue has more than one track for dynamic repeat
|
|
561
624
|
if ((await this.queue.size()) <= 1) {
|
|
562
|
-
throw new
|
|
625
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
626
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_REPEAT,
|
|
627
|
+
message: "The queue size must be greater than 1.",
|
|
628
|
+
});
|
|
563
629
|
}
|
|
564
630
|
// Clone the current player state for comparison
|
|
565
631
|
const oldPlayer = this ? { ...this } : null;
|
|
@@ -633,12 +699,25 @@ class Player {
|
|
|
633
699
|
async stop(amount) {
|
|
634
700
|
const oldPlayer = { ...this };
|
|
635
701
|
let removedTracks = [];
|
|
702
|
+
const current = await this.queue.getCurrent(); // may be null
|
|
636
703
|
if (typeof amount === "number" && amount > 1) {
|
|
637
|
-
|
|
638
|
-
|
|
704
|
+
const queueSize = await this.queue.size();
|
|
705
|
+
if (amount > queueSize) {
|
|
706
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
707
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_QUEUE_EMPTY,
|
|
708
|
+
message: "The amount of tracks to remove is greater than the queue size.",
|
|
709
|
+
});
|
|
710
|
+
}
|
|
639
711
|
removedTracks = await this.queue.getSlice(0, amount - 1);
|
|
640
712
|
await this.queue.modifyAt(0, amount - 1);
|
|
713
|
+
const toAdd = [];
|
|
714
|
+
if (current)
|
|
715
|
+
toAdd.push(current);
|
|
716
|
+
toAdd.push(...removedTracks);
|
|
717
|
+
await this.queue.addPrevious(toAdd);
|
|
641
718
|
}
|
|
719
|
+
// This will trigger trackEnd for the current track; since we already added current,
|
|
720
|
+
// addPrevious will ignore duplicates.
|
|
642
721
|
this.node.rest.updatePlayer({
|
|
643
722
|
guildId: this.guildId,
|
|
644
723
|
data: {
|
|
@@ -663,8 +742,12 @@ class Player {
|
|
|
663
742
|
*/
|
|
664
743
|
async pause(pause) {
|
|
665
744
|
// Validate the pause parameter to ensure it's a boolean.
|
|
666
|
-
if (typeof pause !== "boolean")
|
|
667
|
-
throw new
|
|
745
|
+
if (typeof pause !== "boolean") {
|
|
746
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
747
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_PAUSE,
|
|
748
|
+
message: "Pause must be a boolean.",
|
|
749
|
+
});
|
|
750
|
+
}
|
|
668
751
|
// If the pause state is already as desired or there are no tracks, return early.
|
|
669
752
|
if (this.paused === pause || !this.queue.totalSize)
|
|
670
753
|
return this;
|
|
@@ -698,19 +781,33 @@ class Player {
|
|
|
698
781
|
* @throws {Error} If there are no previous tracks in the queue.
|
|
699
782
|
* @emits {PlayerStateUpdate} - With {@link PlayerStateEventTypes.TrackChange} as the change type.
|
|
700
783
|
*/
|
|
701
|
-
async previous() {
|
|
702
|
-
//
|
|
784
|
+
async previous(addBackToQueue = true) {
|
|
785
|
+
// Pop the most recent previous track (from tail)
|
|
703
786
|
const lastTrack = await this.queue.popPrevious();
|
|
704
787
|
if (!lastTrack) {
|
|
705
788
|
await this.queue.clearPrevious();
|
|
706
|
-
|
|
789
|
+
const error = new MagmastreamError_1.MagmaStreamError({
|
|
790
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_PREVIOUS_EMPTY,
|
|
791
|
+
message: "Previous queue is empty.",
|
|
792
|
+
});
|
|
793
|
+
console.error(error);
|
|
794
|
+
return this;
|
|
707
795
|
}
|
|
708
796
|
// Capture the current state of the player before making changes.
|
|
709
797
|
const oldPlayer = { ...this };
|
|
710
|
-
//
|
|
798
|
+
// Prevent re-adding the current track
|
|
711
799
|
this.set("skipFlag", true);
|
|
712
|
-
|
|
713
|
-
|
|
800
|
+
// Add the current track to the queue if addBackToQueue is true
|
|
801
|
+
if (addBackToQueue) {
|
|
802
|
+
const currentPlayingTrack = await this.queue.getCurrent();
|
|
803
|
+
if (currentPlayingTrack) {
|
|
804
|
+
await this.queue.add(currentPlayingTrack, 0);
|
|
805
|
+
}
|
|
806
|
+
await this.play(lastTrack);
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
await this.play(lastTrack);
|
|
810
|
+
}
|
|
714
811
|
this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
|
|
715
812
|
changeType: Enums_1.PlayerStateEventTypes.TrackChange,
|
|
716
813
|
details: {
|
|
@@ -734,7 +831,10 @@ class Player {
|
|
|
734
831
|
position = Number(position);
|
|
735
832
|
// Check if the position is valid.
|
|
736
833
|
if (isNaN(position)) {
|
|
737
|
-
throw new
|
|
834
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
835
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_SEEK,
|
|
836
|
+
message: "Position must be a number.",
|
|
837
|
+
});
|
|
738
838
|
}
|
|
739
839
|
// Get the old player state.
|
|
740
840
|
const oldPlayer = this ? { ...this } : null;
|
|
@@ -798,8 +898,14 @@ class Player {
|
|
|
798
898
|
*/
|
|
799
899
|
async moveNode(identifier) {
|
|
800
900
|
const node = this.manager.nodes.get(identifier);
|
|
801
|
-
if (!node)
|
|
802
|
-
|
|
901
|
+
if (!node) {
|
|
902
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Tried to move to non-existent node: ${identifier}`);
|
|
903
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
904
|
+
code: Enums_1.MagmaStreamErrorCode.MANAGER_NODE_NOT_FOUND,
|
|
905
|
+
message: "Node not found.",
|
|
906
|
+
context: { identifier },
|
|
907
|
+
});
|
|
908
|
+
}
|
|
803
909
|
if (this.state !== Enums_1.StateTypes.Connected) {
|
|
804
910
|
return this;
|
|
805
911
|
}
|
|
@@ -814,7 +920,12 @@ class Player {
|
|
|
814
920
|
const token = this.voiceState?.event?.token;
|
|
815
921
|
const endpoint = this.voiceState?.event?.endpoint;
|
|
816
922
|
if (!sessionId || !token || !endpoint) {
|
|
817
|
-
|
|
923
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Voice state is not properly initialized for player ${this.guildId}. The bot might not be connected to a voice channel.`);
|
|
924
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
925
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_STATE_INVALID,
|
|
926
|
+
message: `Voice state is not properly initialized. The bot might not be connected to a voice channel.`,
|
|
927
|
+
context: { guildId: this.guildId },
|
|
928
|
+
});
|
|
818
929
|
}
|
|
819
930
|
await this.node.rest.destroyPlayer(this.guildId).catch(() => { });
|
|
820
931
|
this.manager.players.delete(this.guildId);
|
|
@@ -826,8 +937,17 @@ class Player {
|
|
|
826
937
|
});
|
|
827
938
|
await this.filters.updateFilters();
|
|
828
939
|
}
|
|
829
|
-
catch (
|
|
830
|
-
|
|
940
|
+
catch (err) {
|
|
941
|
+
const error = err instanceof MagmastreamError_1.MagmaStreamError
|
|
942
|
+
? err
|
|
943
|
+
: new MagmastreamError_1.MagmaStreamError({
|
|
944
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_MOVE_FAILED,
|
|
945
|
+
message: "Error moving player to node.",
|
|
946
|
+
cause: err,
|
|
947
|
+
context: { guildId: this.guildId },
|
|
948
|
+
});
|
|
949
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, error);
|
|
950
|
+
console.error(error);
|
|
831
951
|
}
|
|
832
952
|
}
|
|
833
953
|
/**
|
|
@@ -839,12 +959,24 @@ class Player {
|
|
|
839
959
|
* @returns {Promise<Player>} - The new player instance.
|
|
840
960
|
*/
|
|
841
961
|
async switchGuild(newOptions, force = false) {
|
|
842
|
-
if (!newOptions.guildId)
|
|
843
|
-
throw new
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
962
|
+
if (!newOptions.guildId) {
|
|
963
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
964
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
|
|
965
|
+
message: "guildId is required for switchGuild",
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
if (!newOptions.voiceChannelId) {
|
|
969
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
970
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
|
|
971
|
+
message: "voiceChannelId is required for switchGuild",
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
if (!newOptions.textChannelId) {
|
|
975
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
976
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
|
|
977
|
+
message: "textChannelId is required for switchGuild",
|
|
978
|
+
});
|
|
979
|
+
}
|
|
848
980
|
// Check if a player already exists for the new guild
|
|
849
981
|
let newPlayer = this.manager.getPlayer(newOptions.guildId);
|
|
850
982
|
// If the player already exists and force is false, return the existing player
|
|
@@ -943,14 +1075,8 @@ class Player {
|
|
|
943
1075
|
* Retrieves the current lyrics for the playing track.
|
|
944
1076
|
* @param skipTrackSource - Indicates whether to skip the track source when fetching lyrics.
|
|
945
1077
|
* @returns {Promise<Lyrics>} - The lyrics of the current track.
|
|
946
|
-
* @throws {RangeError} - If the 'lavalyrics-plugin' is not available on the Lavalink node.
|
|
947
1078
|
*/
|
|
948
1079
|
async getCurrentLyrics(skipTrackSource = false) {
|
|
949
|
-
// Check if the 'lavalyrics-plugin' is available on the node
|
|
950
|
-
const hasLyricsPlugin = this.node.info.plugins.some((plugin) => plugin.name === "lavalyrics-plugin");
|
|
951
|
-
if (!hasLyricsPlugin) {
|
|
952
|
-
throw new RangeError(`There is no lavalyrics-plugin available in the Lavalink node: ${this.node.options.identifier}`);
|
|
953
|
-
}
|
|
954
1080
|
// Fetch the lyrics for the current track from the Lavalink node
|
|
955
1081
|
let result = (await this.node.getLyrics(await this.queue.getCurrent(), skipTrackSource));
|
|
956
1082
|
// If no lyrics are found, return a default empty lyrics object
|
|
@@ -971,8 +1097,13 @@ class Player {
|
|
|
971
1097
|
* @throws {Error} - If the node is not a NodeLink.
|
|
972
1098
|
*/
|
|
973
1099
|
async setupVoiceReceiver() {
|
|
974
|
-
if (!this.node.isNodeLink)
|
|
975
|
-
throw new
|
|
1100
|
+
if (!this.node.isNodeLink) {
|
|
1101
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
1102
|
+
code: Enums_1.MagmaStreamErrorCode.NODE_PROTOCOL_ERROR,
|
|
1103
|
+
message: `The node is not a NodeLink, cannot setup voice receiver.`,
|
|
1104
|
+
context: { identifier: this.node.options.identifier },
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
976
1107
|
if (this.voiceReceiverWsClient)
|
|
977
1108
|
await this.removeVoiceReceiver();
|
|
978
1109
|
const headers = {
|
|
@@ -994,8 +1125,13 @@ class Player {
|
|
|
994
1125
|
* @throws {Error} - If the node is not a NodeLink.
|
|
995
1126
|
*/
|
|
996
1127
|
async removeVoiceReceiver() {
|
|
997
|
-
if (!this.node.isNodeLink)
|
|
998
|
-
throw new
|
|
1128
|
+
if (!this.node.isNodeLink) {
|
|
1129
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
1130
|
+
code: Enums_1.MagmaStreamErrorCode.NODE_PROTOCOL_ERROR,
|
|
1131
|
+
message: `The node is not a NodeLink, cannot remove voice receiver.`,
|
|
1132
|
+
context: { identifier: this.node.options.identifier },
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
999
1135
|
if (this.voiceReceiverWsClient) {
|
|
1000
1136
|
this.voiceReceiverWsClient.close(1000, "destroy");
|
|
1001
1137
|
this.voiceReceiverWsClient.removeAllListeners();
|
|
@@ -1021,8 +1157,13 @@ class Player {
|
|
|
1021
1157
|
*/
|
|
1022
1158
|
async reconnectVoiceReceiver() {
|
|
1023
1159
|
this.voiceReceiverReconnectTimeout = setTimeout(async () => {
|
|
1024
|
-
if (this.voiceReceiverAttempt > this.voiceReceiverReconnectTries)
|
|
1025
|
-
throw new
|
|
1160
|
+
if (this.voiceReceiverAttempt > this.voiceReceiverReconnectTries) {
|
|
1161
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
1162
|
+
code: Enums_1.MagmaStreamErrorCode.PLAYER_VOICE_RECEIVER_ERROR,
|
|
1163
|
+
message: `Failed to reconnect to voice receiver for player ${this.guildId}`,
|
|
1164
|
+
context: { identifier: this.node.options.identifier },
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1026
1167
|
this.voiceReceiverWsClient?.removeAllListeners();
|
|
1027
1168
|
this.voiceReceiverWsClient = null;
|
|
1028
1169
|
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[PLAYER] Reconnecting to voice receiver for player ${this.guildId}`);
|
package/dist/structures/Rest.js
CHANGED
|
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const axios_1 = tslib_1.__importDefault(require("axios"));
|
|
6
6
|
const Enums_1 = require("./Enums");
|
|
7
7
|
const Utils_1 = require("./Utils");
|
|
8
|
+
const MagmastreamError_1 = require("./MagmastreamError");
|
|
8
9
|
/** Handles the requests sent to the Lavalink REST API. */
|
|
9
10
|
class Rest {
|
|
10
11
|
/** The Node that this Rest instance is connected to. */
|
|
@@ -38,12 +39,12 @@ class Rest {
|
|
|
38
39
|
return this.sessionId;
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
|
-
* Retrieves
|
|
42
|
+
* Retrieves one the player that is currently running on the node.
|
|
42
43
|
* @returns {Promise<unknown>} Returns the result of the GET request.
|
|
43
44
|
*/
|
|
44
|
-
async
|
|
45
|
+
async getPlayer(guildId) {
|
|
45
46
|
// Send a GET request to the Lavalink Node to retrieve all the players.
|
|
46
|
-
const result = await this.get(`/v4/sessions/${this.sessionId}/players`);
|
|
47
|
+
const result = (await this.get(`/v4/sessions/${this.sessionId}/players/${guildId}`));
|
|
47
48
|
// Log the result of the request.
|
|
48
49
|
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Getting all players on node: ${this.node.options.identifier} : ${Utils_1.JSONUtils.safe(result, 2)}`);
|
|
49
50
|
// Return the result of the request.
|
|
@@ -93,7 +94,7 @@ class Rest {
|
|
|
93
94
|
* @returns {Promise<unknown>} The response data of the request.
|
|
94
95
|
*/
|
|
95
96
|
async request(method, endpoint, body) {
|
|
96
|
-
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] ${method}
|
|
97
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] ${method} request to ${endpoint} with body: ${Utils_1.JSONUtils.safe(body, 2)}`);
|
|
97
98
|
const config = {
|
|
98
99
|
method,
|
|
99
100
|
url: this.url + endpoint,
|
|
@@ -108,19 +109,29 @@ class Rest {
|
|
|
108
109
|
const response = await (0, axios_1.default)(config);
|
|
109
110
|
return response.data;
|
|
110
111
|
}
|
|
111
|
-
catch (
|
|
112
|
+
catch (err) {
|
|
113
|
+
const error = err;
|
|
112
114
|
if (!error.response) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
116
|
+
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
|
|
117
|
+
message: `No response from node ${this.node.options.identifier}: ${error.message}`,
|
|
118
|
+
});
|
|
115
119
|
}
|
|
116
|
-
|
|
120
|
+
const data = error.response.data;
|
|
121
|
+
if (data?.message === "Guild not found") {
|
|
117
122
|
return [];
|
|
118
123
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
if (error.response.status === 401) {
|
|
125
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
126
|
+
code: Enums_1.MagmaStreamErrorCode.REST_UNAUTHORIZED,
|
|
127
|
+
message: `Unauthorized access to node ${this.node.options.identifier}`,
|
|
128
|
+
});
|
|
122
129
|
}
|
|
123
|
-
|
|
130
|
+
const dataMessage = typeof data === "string" ? data : data?.message ? data.message : Utils_1.JSONUtils.safe(data, 2);
|
|
131
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
132
|
+
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
|
|
133
|
+
message: `Request to node ${this.node.options.identifier} failed with status ${error.response.status}: ${dataMessage}`,
|
|
134
|
+
});
|
|
124
135
|
}
|
|
125
136
|
}
|
|
126
137
|
/**
|