magmastream 2.9.0-dev.1 → 2.9.0-dev.11
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 +1 -1
- package/dist/index.d.ts +155 -45
- package/dist/storage/CollectionPlayerStore.js +80 -0
- package/dist/storage/RedisPlayerStore.js +159 -0
- package/dist/structures/Manager.js +59 -21
- package/dist/structures/Node.js +46 -37
- package/dist/structures/Player.js +45 -42
- package/dist/structures/Queue.js +313 -210
- package/dist/structures/RedisQueue.js +350 -0
- package/dist/structures/Utils.js +345 -344
- package/dist/utils/logExecutionTime.js +11 -0
- package/dist/utils/managerCheck.js +8 -5
- package/package.json +6 -5
|
@@ -9,6 +9,7 @@ const Queue_1 = require("./Queue");
|
|
|
9
9
|
const Utils_1 = require("./Utils");
|
|
10
10
|
const _ = tslib_1.__importStar(require("lodash"));
|
|
11
11
|
const playerCheck_1 = tslib_1.__importDefault(require("../utils/playerCheck"));
|
|
12
|
+
const RedisQueue_1 = require("./RedisQueue");
|
|
12
13
|
class Player {
|
|
13
14
|
options;
|
|
14
15
|
/** The Queue for the Player. */
|
|
@@ -50,7 +51,7 @@ class Player {
|
|
|
50
51
|
/** The autoplay state of the player. */
|
|
51
52
|
isAutoplay = false;
|
|
52
53
|
/** The number of times to try autoplay before emitting queueEnd. */
|
|
53
|
-
autoplayTries =
|
|
54
|
+
autoplayTries = 3;
|
|
54
55
|
static _manager;
|
|
55
56
|
data = {};
|
|
56
57
|
dynamicLoopInterval = null;
|
|
@@ -67,10 +68,6 @@ class Player {
|
|
|
67
68
|
this.manager = Utils_1.Structure.get("Player")._manager;
|
|
68
69
|
if (!this.manager)
|
|
69
70
|
throw new RangeError("Manager has not been initiated.");
|
|
70
|
-
// If a player with the same guild ID already exists, return it.
|
|
71
|
-
if (this.manager.players.has(options.guildId)) {
|
|
72
|
-
return this.manager.players.get(options.guildId);
|
|
73
|
-
}
|
|
74
71
|
// Check the player options for errors.
|
|
75
72
|
(0, playerCheck_1.default)(options);
|
|
76
73
|
// Set the guild ID and voice state.
|
|
@@ -91,8 +88,15 @@ class Player {
|
|
|
91
88
|
if (!this.node)
|
|
92
89
|
throw new RangeError("No available nodes.");
|
|
93
90
|
// Initialize the queue with the guild ID and manager.
|
|
94
|
-
this.
|
|
95
|
-
|
|
91
|
+
if (this.manager.options.stateStorage.type === Manager_1.StateStorageType.Redis) {
|
|
92
|
+
this.queue = new RedisQueue_1.RedisQueue(this.guildId, this.manager);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.queue = new Queue_1.Queue(this.guildId, this.manager);
|
|
96
|
+
}
|
|
97
|
+
if (this.queue instanceof Queue_1.Queue) {
|
|
98
|
+
this.queue.previous = [];
|
|
99
|
+
}
|
|
96
100
|
// Add the player to the manager's player collection.
|
|
97
101
|
this.manager.players.set(options.guildId, this);
|
|
98
102
|
// Set the initial volume.
|
|
@@ -225,7 +229,7 @@ class Player {
|
|
|
225
229
|
await this.disconnect();
|
|
226
230
|
}
|
|
227
231
|
await this.node.rest.destroyPlayer(this.guildId);
|
|
228
|
-
this.queue.clear();
|
|
232
|
+
await this.queue.clear();
|
|
229
233
|
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, null, {
|
|
230
234
|
changeType: Manager_1.PlayerStateEventTypes.PlayerDestroy,
|
|
231
235
|
});
|
|
@@ -307,9 +311,9 @@ class Player {
|
|
|
307
311
|
}
|
|
308
312
|
async play(optionsOrTrack, playOptions) {
|
|
309
313
|
if (typeof optionsOrTrack !== "undefined" && Utils_1.TrackUtils.validate(optionsOrTrack)) {
|
|
310
|
-
this.queue.
|
|
314
|
+
await this.queue.setCurrent(optionsOrTrack);
|
|
311
315
|
}
|
|
312
|
-
if (!this.queue.
|
|
316
|
+
if (!(await this.queue.getCurrent()))
|
|
313
317
|
throw new RangeError("No current track.");
|
|
314
318
|
const finalOptions = playOptions
|
|
315
319
|
? playOptions
|
|
@@ -319,7 +323,7 @@ class Player {
|
|
|
319
323
|
await this.node.rest.updatePlayer({
|
|
320
324
|
guildId: this.guildId,
|
|
321
325
|
data: {
|
|
322
|
-
encodedTrack: this.queue.
|
|
326
|
+
encodedTrack: (await this.queue.getCurrent()).track,
|
|
323
327
|
...finalOptions,
|
|
324
328
|
},
|
|
325
329
|
});
|
|
@@ -375,7 +379,7 @@ class Player {
|
|
|
375
379
|
* @returns {Promise<Track[]>} - Array of recommended tracks.
|
|
376
380
|
*/
|
|
377
381
|
async getRecommendedTracks(track) {
|
|
378
|
-
const tracks = await Utils_1.AutoPlayUtils.getRecommendedTracks(
|
|
382
|
+
const tracks = await Utils_1.AutoPlayUtils.getRecommendedTracks(track);
|
|
379
383
|
return tracks;
|
|
380
384
|
}
|
|
381
385
|
/**
|
|
@@ -509,13 +513,13 @@ class Player {
|
|
|
509
513
|
* @throws {TypeError} If the repeat parameter is not a boolean.
|
|
510
514
|
* @throws {RangeError} If the queue size is less than or equal to 1.
|
|
511
515
|
*/
|
|
512
|
-
setDynamicRepeat(repeat, ms) {
|
|
516
|
+
async setDynamicRepeat(repeat, ms) {
|
|
513
517
|
// Validate the repeat parameter
|
|
514
518
|
if (typeof repeat !== "boolean") {
|
|
515
519
|
throw new TypeError('Repeat can only be "true" or "false".');
|
|
516
520
|
}
|
|
517
521
|
// Ensure the queue has more than one track for dynamic repeat
|
|
518
|
-
if (this.queue.size <= 1) {
|
|
522
|
+
if ((await this.queue.size()) <= 1) {
|
|
519
523
|
throw new RangeError("The queue size must be greater than 1.");
|
|
520
524
|
}
|
|
521
525
|
// Clone the current player state for comparison
|
|
@@ -526,15 +530,14 @@ class Player {
|
|
|
526
530
|
this.queueRepeat = false;
|
|
527
531
|
this.dynamicRepeat = true;
|
|
528
532
|
// Set an interval to shuffle the queue periodically
|
|
529
|
-
this.dynamicLoopInterval = setInterval(() => {
|
|
533
|
+
this.dynamicLoopInterval = setInterval(async () => {
|
|
530
534
|
if (!this.dynamicRepeat)
|
|
531
535
|
return;
|
|
532
536
|
// Shuffle the queue and replace it with the shuffled tracks
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
});
|
|
537
|
+
const tracks = await this.queue.getTracks();
|
|
538
|
+
const shuffled = _.shuffle(tracks);
|
|
539
|
+
await this.queue.clear();
|
|
540
|
+
await this.queue.add(shuffled);
|
|
538
541
|
}, ms);
|
|
539
542
|
// Store the ms value
|
|
540
543
|
this.dynamicRepeatIntervalMs = ms;
|
|
@@ -565,9 +568,9 @@ class Player {
|
|
|
565
568
|
*/
|
|
566
569
|
async restart() {
|
|
567
570
|
// Check if there is a current track in the queue
|
|
568
|
-
if (!this.queue.
|
|
571
|
+
if (!(await this.queue.getCurrent())?.track) {
|
|
569
572
|
// If the queue has tracks, play the next one
|
|
570
|
-
if (this.queue.
|
|
573
|
+
if (await this.queue.size())
|
|
571
574
|
await this.play();
|
|
572
575
|
return this;
|
|
573
576
|
}
|
|
@@ -576,7 +579,7 @@ class Player {
|
|
|
576
579
|
guildId: this.guildId,
|
|
577
580
|
data: {
|
|
578
581
|
position: 0,
|
|
579
|
-
encodedTrack: this.queue.
|
|
582
|
+
encodedTrack: (await this.queue.getCurrent())?.track,
|
|
580
583
|
},
|
|
581
584
|
});
|
|
582
585
|
return this;
|
|
@@ -591,10 +594,10 @@ class Player {
|
|
|
591
594
|
const oldPlayer = { ...this };
|
|
592
595
|
let removedTracks = [];
|
|
593
596
|
if (typeof amount === "number" && amount > 1) {
|
|
594
|
-
if (amount > this.queue.
|
|
597
|
+
if (amount > (await this.queue.size()))
|
|
595
598
|
throw new RangeError("Cannot skip more than the queue length.");
|
|
596
|
-
removedTracks = this.queue.
|
|
597
|
-
this.queue.
|
|
599
|
+
removedTracks = await this.queue.getSlice(0, amount - 1);
|
|
600
|
+
await this.queue.modifyAt(0, amount - 1);
|
|
598
601
|
}
|
|
599
602
|
this.node.rest.updatePlayer({
|
|
600
603
|
guildId: this.guildId,
|
|
@@ -654,7 +657,7 @@ class Player {
|
|
|
654
657
|
*/
|
|
655
658
|
async previous() {
|
|
656
659
|
// Check if there are previous tracks in the queue.
|
|
657
|
-
if (!this.queue.
|
|
660
|
+
if (!(await this.queue.getPrevious()).length) {
|
|
658
661
|
throw new Error("No previous track available.");
|
|
659
662
|
}
|
|
660
663
|
// Capture the current state of the player before making changes.
|
|
@@ -662,7 +665,7 @@ class Player {
|
|
|
662
665
|
// Store the current track before changing it.
|
|
663
666
|
// let currentTrackBeforeChange: Track | null = this.queue.current ? (this.queue.current as Track) : null;
|
|
664
667
|
// Get the last played track and remove it from the history
|
|
665
|
-
const lastTrack = this.queue.
|
|
668
|
+
const lastTrack = (await this.queue.getPrevious()).pop();
|
|
666
669
|
// Set the skip flag to true to prevent the onTrackEnd event from playing the next track.
|
|
667
670
|
this.set("skipFlag", true);
|
|
668
671
|
await this.play(lastTrack);
|
|
@@ -688,7 +691,7 @@ class Player {
|
|
|
688
691
|
* @emits {PlayerStateUpdate} - With {@link PlayerStateEventTypes.TrackChange} as the change type.
|
|
689
692
|
*/
|
|
690
693
|
async seek(position) {
|
|
691
|
-
if (!this.queue.
|
|
694
|
+
if (!(await this.queue.getCurrent()))
|
|
692
695
|
return undefined;
|
|
693
696
|
position = Number(position);
|
|
694
697
|
// Check if the position is valid.
|
|
@@ -698,8 +701,8 @@ class Player {
|
|
|
698
701
|
// Get the old player state.
|
|
699
702
|
const oldPlayer = this ? { ...this } : null;
|
|
700
703
|
// Clamp the position to ensure it is within the valid range.
|
|
701
|
-
if (position < 0 || position > this.queue.
|
|
702
|
-
position = Math.max(Math.min(position, this.queue.
|
|
704
|
+
if (position < 0 || position > (await this.queue.getCurrent()).duration) {
|
|
705
|
+
position = Math.max(Math.min(position, (await this.queue.getCurrent()).duration), 0);
|
|
703
706
|
}
|
|
704
707
|
// Update the player's position.
|
|
705
708
|
this.position = position;
|
|
@@ -764,7 +767,7 @@ class Player {
|
|
|
764
767
|
try {
|
|
765
768
|
const playerPosition = this.position;
|
|
766
769
|
const { sessionId, event: { token, endpoint }, } = this.voiceState;
|
|
767
|
-
const currentTrack = this.queue.
|
|
770
|
+
const currentTrack = (await this.queue.getCurrent()) ? await this.queue.getCurrent() : null;
|
|
768
771
|
await this.node.rest.destroyPlayer(this.guildId).catch(() => { });
|
|
769
772
|
this.manager.players.delete(this.guildId);
|
|
770
773
|
this.node = node;
|
|
@@ -795,7 +798,7 @@ class Player {
|
|
|
795
798
|
if (!newOptions.textChannelId)
|
|
796
799
|
throw new Error("Text channel ID is required");
|
|
797
800
|
// Check if a player already exists for the new guild
|
|
798
|
-
let newPlayer = this.manager.
|
|
801
|
+
let newPlayer = await this.manager.getPlayer(newOptions.guildId);
|
|
799
802
|
// If the player already exists and force is false, return the existing player
|
|
800
803
|
if (newPlayer && !force)
|
|
801
804
|
return newPlayer;
|
|
@@ -806,9 +809,9 @@ class Player {
|
|
|
806
809
|
volume: this.volume,
|
|
807
810
|
position: this.position,
|
|
808
811
|
queue: {
|
|
809
|
-
current: this.queue.
|
|
810
|
-
tracks: [...this.queue],
|
|
811
|
-
previous: [...this.queue.
|
|
812
|
+
current: await this.queue.getCurrent(),
|
|
813
|
+
tracks: [...(await this.queue.getTracks())],
|
|
814
|
+
previous: [...(await this.queue.getPrevious())],
|
|
812
815
|
},
|
|
813
816
|
trackRepeat: this.trackRepeat,
|
|
814
817
|
queueRepeat: this.queueRepeat,
|
|
@@ -828,7 +831,7 @@ class Player {
|
|
|
828
831
|
newOptions.selfMute = newOptions.selfMute ?? oldPlayerProperties.selfMute;
|
|
829
832
|
newOptions.volume = newOptions.volume ?? oldPlayerProperties.volume;
|
|
830
833
|
// Deep clone the current player
|
|
831
|
-
const clonedPlayer = this.manager.create(newOptions);
|
|
834
|
+
const clonedPlayer = await this.manager.create(newOptions);
|
|
832
835
|
// Connect the cloned player to the new voice channel
|
|
833
836
|
clonedPlayer.connect();
|
|
834
837
|
// Update the player's state on the Lavalink node
|
|
@@ -841,9 +844,9 @@ class Player {
|
|
|
841
844
|
encodedTrack: oldPlayerProperties.queue.current?.track,
|
|
842
845
|
},
|
|
843
846
|
});
|
|
844
|
-
clonedPlayer.queue.
|
|
845
|
-
clonedPlayer.queue.
|
|
846
|
-
clonedPlayer.queue.add(oldPlayerProperties.queue.tracks);
|
|
847
|
+
await clonedPlayer.queue.setCurrent(oldPlayerProperties.queue.current);
|
|
848
|
+
await clonedPlayer.queue.addPrevious(oldPlayerProperties.queue.previous);
|
|
849
|
+
await clonedPlayer.queue.add(oldPlayerProperties.queue.tracks);
|
|
847
850
|
clonedPlayer.filters = oldPlayerProperties.filters;
|
|
848
851
|
clonedPlayer.isAutoplay = oldPlayerProperties.isAutoplay;
|
|
849
852
|
clonedPlayer.nowPlayingMessage = oldPlayerProperties.nowPlayingMessage;
|
|
@@ -858,7 +861,7 @@ class Player {
|
|
|
858
861
|
// Debug information
|
|
859
862
|
const debugInfo = {
|
|
860
863
|
success: true,
|
|
861
|
-
message: `Transferred ${clonedPlayer.queue.
|
|
864
|
+
message: `Transferred ${await clonedPlayer.queue.size()} tracks successfully to <#${newOptions.voiceChannelId}> bound to <#${newOptions.textChannelId}>.`,
|
|
862
865
|
player: {
|
|
863
866
|
guildId: clonedPlayer.guildId,
|
|
864
867
|
voiceChannelId: clonedPlayer.voiceChannelId,
|
|
@@ -885,7 +888,7 @@ class Player {
|
|
|
885
888
|
throw new RangeError(`There is no lavalyrics-plugin available in the Lavalink node: ${this.node.options.identifier}`);
|
|
886
889
|
}
|
|
887
890
|
// Fetch the lyrics for the current track from the Lavalink node
|
|
888
|
-
let result = (await this.node.getLyrics(this.queue.
|
|
891
|
+
let result = (await this.node.getLyrics(await this.queue.getCurrent(), skipTrackSource));
|
|
889
892
|
// If no lyrics are found, return a default empty lyrics object
|
|
890
893
|
if (!result) {
|
|
891
894
|
result = {
|