magmastream 2.9.0-dev.10 → 2.9.0-dev.12
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/structures/Queue.js +260 -210
- package/dist/structures/RedisQueue.js +250 -204
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
| [HamBot](https://discord.com/oauth2/authorize?client_id=1049314312776335390) | yanishamburger|
|
|
101
101
|
| [Miyu](https://discord.com/oauth2/authorize?client_id=1277180179273482280&permissions=572851999731703&response_type=code&redirect_uri=https%3A%2F%2Fdiscord.gg%2Ftn3nbFB8nX&integration_type=0&scope=identify+applications.commands+bot) | Kenver |
|
|
102
102
|
| [Savage Bot](https://discord.com/oauth2/authorize?client_id=823703707522433054&permissions=8&scope=bot%20applications.commands) | Savage
|
|
103
|
-
| [
|
|
103
|
+
| [lost](https://discord.com/oauth2/authorize?client_id=1280681209604739204) | pomice
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
Want to showcase your bot? Feel free to create a pull request and add it to our growing list of amazing bots powered by Magmastream!
|
package/dist/structures/Queue.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Queue = void 0;
|
|
4
4
|
const Manager_1 = require("./Manager"); // Import Manager to access emit method
|
|
5
|
+
const logExecutionTime_1 = require("../utils/logExecutionTime");
|
|
5
6
|
/**
|
|
6
7
|
* The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
|
|
7
8
|
*/
|
|
@@ -27,32 +28,44 @@ class Queue extends Array {
|
|
|
27
28
|
this.guildId = guildId;
|
|
28
29
|
}
|
|
29
30
|
async getCurrent() {
|
|
30
|
-
return
|
|
31
|
+
return (0, logExecutionTime_1.logExecutionTime)("getCurrent (Collection)", async () => {
|
|
32
|
+
return this.current;
|
|
33
|
+
});
|
|
31
34
|
}
|
|
32
35
|
async setCurrent(track) {
|
|
33
|
-
|
|
36
|
+
return (0, logExecutionTime_1.logExecutionTime)("setCurrent (Collection)", async () => {
|
|
37
|
+
this.current = track;
|
|
38
|
+
});
|
|
34
39
|
}
|
|
35
40
|
async getPrevious() {
|
|
36
|
-
return
|
|
41
|
+
return (0, logExecutionTime_1.logExecutionTime)("getPrevious (Collection)", async () => {
|
|
42
|
+
return this.previous;
|
|
43
|
+
});
|
|
37
44
|
}
|
|
38
45
|
async addPrevious(track) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
return (0, logExecutionTime_1.logExecutionTime)("addPrevious (Collection)", async () => {
|
|
47
|
+
if (Array.isArray(track)) {
|
|
48
|
+
this.previous.unshift(...track);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.previous.unshift(track);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
45
54
|
}
|
|
46
55
|
async clearPrevious() {
|
|
47
|
-
|
|
56
|
+
return (0, logExecutionTime_1.logExecutionTime)("clearPrevious (Collection)", async () => {
|
|
57
|
+
this.previous = [];
|
|
58
|
+
});
|
|
48
59
|
}
|
|
49
60
|
/**
|
|
50
61
|
* The total duration of the queue in milliseconds.
|
|
51
62
|
* This includes the duration of the currently playing track.
|
|
52
63
|
*/
|
|
53
64
|
async duration() {
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
return (0, logExecutionTime_1.logExecutionTime)("duration (Collection)", async () => {
|
|
66
|
+
const current = this.current?.duration ?? 0;
|
|
67
|
+
return this.reduce((acc, cur) => acc + (cur.duration || 0), current);
|
|
68
|
+
});
|
|
56
69
|
}
|
|
57
70
|
/**
|
|
58
71
|
* The total size of tracks in the queue including the current track.
|
|
@@ -60,7 +73,9 @@ class Queue extends Array {
|
|
|
60
73
|
* @returns The total size of tracks in the queue including the current track.
|
|
61
74
|
*/
|
|
62
75
|
async totalSize() {
|
|
63
|
-
return
|
|
76
|
+
return (0, logExecutionTime_1.logExecutionTime)("totalSize (Collection)", async () => {
|
|
77
|
+
return this.length + (this.current ? 1 : 0);
|
|
78
|
+
});
|
|
64
79
|
}
|
|
65
80
|
/**
|
|
66
81
|
* The size of tracks in the queue.
|
|
@@ -68,7 +83,9 @@ class Queue extends Array {
|
|
|
68
83
|
* @returns The size of tracks in the queue.
|
|
69
84
|
*/
|
|
70
85
|
async size() {
|
|
71
|
-
return
|
|
86
|
+
return (0, logExecutionTime_1.logExecutionTime)("size (Collection)", async () => {
|
|
87
|
+
return this.length;
|
|
88
|
+
});
|
|
72
89
|
}
|
|
73
90
|
/**
|
|
74
91
|
* Adds a track to the queue.
|
|
@@ -76,274 +93,307 @@ class Queue extends Array {
|
|
|
76
93
|
* @param [offset=null] The position to add the track(s) at. If not provided, the track(s) will be added at the end of the queue.
|
|
77
94
|
*/
|
|
78
95
|
async add(track, offset) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (Array.isArray(track)) {
|
|
88
|
-
this.current = track.shift() || null;
|
|
89
|
-
this.push(...track);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
this.current = track;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
// If an offset is provided, add the track(s) at that position
|
|
97
|
-
if (typeof offset !== "undefined" && typeof offset === "number") {
|
|
98
|
-
// Validate the offset
|
|
99
|
-
if (isNaN(offset)) {
|
|
100
|
-
throw new RangeError("Offset must be a number.");
|
|
101
|
-
}
|
|
102
|
-
// Make sure the offset is between 0 and the length of the queue
|
|
103
|
-
if (offset < 0 || offset > this.length) {
|
|
104
|
-
throw new RangeError(`Offset must be between 0 and ${this.length}.`);
|
|
105
|
-
}
|
|
106
|
-
// Add the track(s) at the offset position
|
|
96
|
+
return (0, logExecutionTime_1.logExecutionTime)("add (Collection)", async () => {
|
|
97
|
+
// Get the track info as a string
|
|
98
|
+
const trackInfo = Array.isArray(track) ? track.map((t) => JSON.stringify(t, null, 2)).join(", ") : JSON.stringify(track, null, 2);
|
|
99
|
+
// Emit a debug message
|
|
100
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Added ${Array.isArray(track) ? track.length : 1} track(s) to queue: ${trackInfo}`);
|
|
101
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
102
|
+
// If the queue is empty, set the track as the current track
|
|
103
|
+
if (!this.current) {
|
|
107
104
|
if (Array.isArray(track)) {
|
|
108
|
-
this.
|
|
105
|
+
this.current = track.shift() || null;
|
|
106
|
+
this.push(...track);
|
|
109
107
|
}
|
|
110
108
|
else {
|
|
111
|
-
this.
|
|
109
|
+
this.current = track;
|
|
112
110
|
}
|
|
113
111
|
}
|
|
114
112
|
else {
|
|
115
|
-
// If
|
|
116
|
-
if (
|
|
117
|
-
|
|
113
|
+
// If an offset is provided, add the track(s) at that position
|
|
114
|
+
if (typeof offset !== "undefined" && typeof offset === "number") {
|
|
115
|
+
// Validate the offset
|
|
116
|
+
if (isNaN(offset)) {
|
|
117
|
+
throw new RangeError("Offset must be a number.");
|
|
118
|
+
}
|
|
119
|
+
// Make sure the offset is between 0 and the length of the queue
|
|
120
|
+
if (offset < 0 || offset > this.length) {
|
|
121
|
+
throw new RangeError(`Offset must be between 0 and ${this.length}.`);
|
|
122
|
+
}
|
|
123
|
+
// Add the track(s) at the offset position
|
|
124
|
+
if (Array.isArray(track)) {
|
|
125
|
+
this.splice(offset, 0, ...track);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
this.splice(offset, 0, track);
|
|
129
|
+
}
|
|
118
130
|
}
|
|
119
131
|
else {
|
|
120
|
-
|
|
132
|
+
// If no offset is provided, add the track(s) at the end of the queue
|
|
133
|
+
if (Array.isArray(track)) {
|
|
134
|
+
this.push(...track);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.push(track);
|
|
138
|
+
}
|
|
121
139
|
}
|
|
122
140
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
|
|
142
|
+
if (!Array.isArray(track)) {
|
|
143
|
+
const botUser = this.manager.players.get(this.guildId).get("Internal_BotUser");
|
|
144
|
+
if (botUser && botUser.id === track.requester.id) {
|
|
145
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
146
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
147
|
+
details: {
|
|
148
|
+
changeType: "autoPlayAdd",
|
|
149
|
+
tracks: Array.isArray(track) ? track : [track],
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
136
154
|
}
|
|
137
155
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
156
|
+
// Emit a player state update event with the added track(s)
|
|
157
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
158
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
159
|
+
details: {
|
|
160
|
+
changeType: "add",
|
|
161
|
+
tracks: Array.isArray(track) ? track : [track],
|
|
162
|
+
},
|
|
163
|
+
});
|
|
146
164
|
});
|
|
147
165
|
}
|
|
148
166
|
async remove(startOrPosition = 0, end) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
167
|
+
return (0, logExecutionTime_1.logExecutionTime)("remove (Collection)", async () => {
|
|
168
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
169
|
+
if (typeof end !== "undefined") {
|
|
170
|
+
// Validate input for `start` and `end`
|
|
171
|
+
if (isNaN(Number(startOrPosition)) || isNaN(Number(end))) {
|
|
172
|
+
throw new RangeError(`Invalid "start" or "end" parameter: start = ${startOrPosition}, end = ${end}`);
|
|
173
|
+
}
|
|
174
|
+
if (startOrPosition >= end || startOrPosition >= this.length) {
|
|
175
|
+
throw new RangeError("Invalid range: start should be less than end and within queue length.");
|
|
176
|
+
}
|
|
177
|
+
const removedTracks = this.splice(startOrPosition, end - startOrPosition);
|
|
178
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Removed ${removedTracks.length} track(s) from player: ${this.guildId} from position ${startOrPosition} to ${end}.`);
|
|
179
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
180
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
181
|
+
details: {
|
|
182
|
+
changeType: "remove",
|
|
183
|
+
tracks: removedTracks,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
return removedTracks;
|
|
157
187
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
this.manager.emit(Manager_1.ManagerEventTypes.
|
|
188
|
+
// Single item removal when no end specified
|
|
189
|
+
const removedTrack = this.splice(startOrPosition, 1);
|
|
190
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Removed 1 track from player: ${this.guildId} from position ${startOrPosition}: ${JSON.stringify(removedTrack[0], null, 2)}`);
|
|
191
|
+
// Ensure removedTrack is an array for consistency
|
|
192
|
+
const tracksToEmit = removedTrack.length > 0 ? removedTrack : [];
|
|
193
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
161
194
|
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
162
195
|
details: {
|
|
163
196
|
changeType: "remove",
|
|
164
|
-
tracks:
|
|
197
|
+
tracks: tracksToEmit,
|
|
165
198
|
},
|
|
166
199
|
});
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
// Single item removal when no end specified
|
|
170
|
-
const removedTrack = this.splice(startOrPosition, 1);
|
|
171
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Removed 1 track from player: ${this.guildId} from position ${startOrPosition}: ${JSON.stringify(removedTrack[0], null, 2)}`);
|
|
172
|
-
// Ensure removedTrack is an array for consistency
|
|
173
|
-
const tracksToEmit = removedTrack.length > 0 ? removedTrack : [];
|
|
174
|
-
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, await this.manager.players.get(this.guildId), {
|
|
175
|
-
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
176
|
-
details: {
|
|
177
|
-
changeType: "remove",
|
|
178
|
-
tracks: tracksToEmit,
|
|
179
|
-
},
|
|
200
|
+
return removedTrack;
|
|
180
201
|
});
|
|
181
|
-
return removedTrack;
|
|
182
202
|
}
|
|
183
203
|
/**
|
|
184
204
|
* Clears the queue.
|
|
185
205
|
* This will remove all tracks from the queue and emit a state update event.
|
|
186
206
|
*/
|
|
187
207
|
async clear() {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
208
|
+
return (0, logExecutionTime_1.logExecutionTime)("clear (Collection)", async () => {
|
|
209
|
+
// Capture the current state of the player for event emission.
|
|
210
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
211
|
+
// Remove all items from the queue.
|
|
212
|
+
this.splice(0);
|
|
213
|
+
// Emit an event to update the player state indicating the queue has been cleared.
|
|
214
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, await this.manager.players.get(this.guildId), {
|
|
215
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
216
|
+
details: {
|
|
217
|
+
changeType: "clear",
|
|
218
|
+
tracks: [], // No tracks are left after clearing
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
// Emit a debug message indicating the queue has been cleared for a specific guild ID.
|
|
222
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Cleared the queue for: ${this.guildId}`);
|
|
199
223
|
});
|
|
200
|
-
// Emit a debug message indicating the queue has been cleared for a specific guild ID.
|
|
201
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Cleared the queue for: ${this.guildId}`);
|
|
202
224
|
}
|
|
203
225
|
/**
|
|
204
226
|
* Shuffles the queue.
|
|
205
227
|
* This will randomize the order of the tracks in the queue and emit a state update event.
|
|
206
228
|
*/
|
|
207
229
|
async shuffle() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
230
|
+
return (0, logExecutionTime_1.logExecutionTime)("shuffle (Collection)", async () => {
|
|
231
|
+
// Capture the current state of the player for event emission.
|
|
232
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
233
|
+
// Shuffle the queue.
|
|
234
|
+
for (let i = this.length - 1; i > 0; i--) {
|
|
235
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
236
|
+
[this[i], this[j]] = [this[j], this[i]];
|
|
237
|
+
}
|
|
238
|
+
// Emit an event to update the player state indicating the queue has been shuffled.
|
|
239
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, await this.manager.players.get(this.guildId), {
|
|
240
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
241
|
+
details: {
|
|
242
|
+
changeType: "shuffle",
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
// Emit a debug message indicating the queue has been shuffled for a specific guild ID.
|
|
246
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Shuffled the queue for: ${this.guildId}`);
|
|
221
247
|
});
|
|
222
|
-
// Emit a debug message indicating the queue has been shuffled for a specific guild ID.
|
|
223
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Shuffled the queue for: ${this.guildId}`);
|
|
224
248
|
}
|
|
225
249
|
/**
|
|
226
250
|
* Shuffles the queue to play tracks requested by each user one block at a time.
|
|
227
251
|
*/
|
|
228
252
|
async userBlockShuffle() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
userTracks.
|
|
237
|
-
|
|
238
|
-
userTracks.get(user).push(track);
|
|
239
|
-
});
|
|
240
|
-
// Create a new array for the shuffled queue.
|
|
241
|
-
const shuffledQueue = [];
|
|
242
|
-
// Iterate over the user tracks and add one track from each user to the shuffled queue.
|
|
243
|
-
// This will ensure that all the tracks requested by each user are played in a block order.
|
|
244
|
-
while (shuffledQueue.length < this.length) {
|
|
245
|
-
userTracks.forEach((tracks) => {
|
|
246
|
-
const track = tracks.shift();
|
|
247
|
-
if (track) {
|
|
248
|
-
shuffledQueue.push(track);
|
|
253
|
+
return (0, logExecutionTime_1.logExecutionTime)("userBlockShuffle (Collection)", async () => {
|
|
254
|
+
// Capture the current state of the player for event emission.
|
|
255
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
256
|
+
// Group the tracks in the queue by the user that requested them.
|
|
257
|
+
const userTracks = new Map();
|
|
258
|
+
this.forEach((track) => {
|
|
259
|
+
const user = track.requester.id;
|
|
260
|
+
if (!userTracks.has(user)) {
|
|
261
|
+
userTracks.set(user, []);
|
|
249
262
|
}
|
|
263
|
+
userTracks.get(user).push(track);
|
|
264
|
+
});
|
|
265
|
+
// Create a new array for the shuffled queue.
|
|
266
|
+
const shuffledQueue = [];
|
|
267
|
+
// Iterate over the user tracks and add one track from each user to the shuffled queue.
|
|
268
|
+
// This will ensure that all the tracks requested by each user are played in a block order.
|
|
269
|
+
while (shuffledQueue.length < this.length) {
|
|
270
|
+
userTracks.forEach((tracks) => {
|
|
271
|
+
const track = tracks.shift();
|
|
272
|
+
if (track) {
|
|
273
|
+
shuffledQueue.push(track);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
// Clear the queue and add the shuffled tracks.
|
|
278
|
+
this.splice(0);
|
|
279
|
+
this.add(shuffledQueue);
|
|
280
|
+
// Emit an event to update the player state indicating the queue has been shuffled.
|
|
281
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, await this.manager.players.get(this.guildId), {
|
|
282
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
283
|
+
details: {
|
|
284
|
+
changeType: "userBlock",
|
|
285
|
+
},
|
|
250
286
|
});
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.splice(0);
|
|
254
|
-
this.add(shuffledQueue);
|
|
255
|
-
// Emit an event to update the player state indicating the queue has been shuffled.
|
|
256
|
-
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, await this.manager.players.get(this.guildId), {
|
|
257
|
-
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
258
|
-
details: {
|
|
259
|
-
changeType: "userBlock",
|
|
260
|
-
},
|
|
287
|
+
// Emit a debug message indicating the queue has been shuffled for a specific guild ID.
|
|
288
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] userBlockShuffled the queue for: ${this.guildId}`);
|
|
261
289
|
});
|
|
262
|
-
// Emit a debug message indicating the queue has been shuffled for a specific guild ID.
|
|
263
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] userBlockShuffled the queue for: ${this.guildId}`);
|
|
264
290
|
}
|
|
265
291
|
/**
|
|
266
292
|
* Shuffles the queue to play tracks requested by each user one by one.
|
|
267
293
|
*/
|
|
268
294
|
async roundRobinShuffle() {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
295
|
+
return (0, logExecutionTime_1.logExecutionTime)("roundRobinShuffle (Collection)", async () => {
|
|
296
|
+
// Capture the current state of the player for event emission.
|
|
297
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
298
|
+
// Group the tracks in the queue by the user that requested them.
|
|
299
|
+
const userTracks = new Map();
|
|
300
|
+
// Group the tracks in the queue by the user that requested them.
|
|
301
|
+
this.forEach((track) => {
|
|
302
|
+
const user = track.requester.id;
|
|
303
|
+
if (!userTracks.has(user)) {
|
|
304
|
+
userTracks.set(user, []);
|
|
305
|
+
}
|
|
306
|
+
userTracks.get(user).push(track);
|
|
307
|
+
});
|
|
308
|
+
// Shuffle the tracks of each user.
|
|
309
|
+
userTracks.forEach((tracks) => {
|
|
310
|
+
for (let i = tracks.length - 1; i > 0; i--) {
|
|
311
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
312
|
+
[tracks[i], tracks[j]] = [tracks[j], tracks[i]];
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
// Create a new array for the shuffled queue.
|
|
316
|
+
const shuffledQueue = [];
|
|
317
|
+
// Add the shuffled tracks to the queue in a round-robin fashion.
|
|
318
|
+
const users = Array.from(userTracks.keys());
|
|
319
|
+
const userQueues = users.map((user) => userTracks.get(user));
|
|
320
|
+
const userCount = users.length;
|
|
321
|
+
while (userQueues.some((queue) => queue.length > 0)) {
|
|
322
|
+
for (let i = 0; i < userCount; i++) {
|
|
323
|
+
const queue = userQueues[i];
|
|
324
|
+
if (queue.length > 0) {
|
|
325
|
+
shuffledQueue.push(queue.shift());
|
|
326
|
+
}
|
|
297
327
|
}
|
|
298
328
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
329
|
+
// Clear the queue and add the shuffled tracks.
|
|
330
|
+
this.splice(0);
|
|
331
|
+
this.add(shuffledQueue);
|
|
332
|
+
// Emit an event to update the player state indicating the queue has been shuffled.
|
|
333
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, await this.manager.players.get(this.guildId), {
|
|
334
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
335
|
+
details: {
|
|
336
|
+
changeType: "roundRobin",
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
// Emit a debug message indicating the queue has been shuffled for a specific guild ID.
|
|
340
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
|
|
309
341
|
});
|
|
310
|
-
// Emit a debug message indicating the queue has been shuffled for a specific guild ID.
|
|
311
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
|
|
312
342
|
}
|
|
313
343
|
async dequeue() {
|
|
314
|
-
return
|
|
344
|
+
return (0, logExecutionTime_1.logExecutionTime)("dequeue (Collection)", async () => {
|
|
345
|
+
return super.shift();
|
|
346
|
+
});
|
|
315
347
|
}
|
|
316
348
|
async enqueueFront(track) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
349
|
+
return (0, logExecutionTime_1.logExecutionTime)("enqueueFront (Collection)", async () => {
|
|
350
|
+
if (Array.isArray(track)) {
|
|
351
|
+
this.unshift(...track);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
this.unshift(track);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
323
357
|
}
|
|
324
358
|
async getTracks() {
|
|
325
|
-
return
|
|
359
|
+
return (0, logExecutionTime_1.logExecutionTime)("getTracks (Collection)", async () => {
|
|
360
|
+
return [...this]; // clone to avoid direct mutation
|
|
361
|
+
});
|
|
326
362
|
}
|
|
327
363
|
async getSlice(start, end) {
|
|
328
|
-
return
|
|
364
|
+
return (0, logExecutionTime_1.logExecutionTime)("getSlice (Collection)", async () => {
|
|
365
|
+
return this.slice(start, end); // Native sync method, still wrapped in a Promise
|
|
366
|
+
});
|
|
329
367
|
}
|
|
330
368
|
async modifyAt(start, deleteCount = 0, ...items) {
|
|
331
|
-
return
|
|
369
|
+
return (0, logExecutionTime_1.logExecutionTime)("modifyAt (Collection)", async () => {
|
|
370
|
+
return super.splice(start, deleteCount, ...items);
|
|
371
|
+
});
|
|
332
372
|
}
|
|
333
373
|
async mapAsync(callback) {
|
|
334
|
-
return
|
|
374
|
+
return (0, logExecutionTime_1.logExecutionTime)("mapAsync (Collection)", async () => {
|
|
375
|
+
return this.map(callback);
|
|
376
|
+
});
|
|
335
377
|
}
|
|
336
378
|
async filterAsync(callback) {
|
|
337
|
-
return
|
|
379
|
+
return (0, logExecutionTime_1.logExecutionTime)("filterAsync (Collection)", async () => {
|
|
380
|
+
return this.filter(callback);
|
|
381
|
+
});
|
|
338
382
|
}
|
|
339
383
|
async findAsync(callback) {
|
|
340
|
-
return
|
|
384
|
+
return (0, logExecutionTime_1.logExecutionTime)("findAsync (Collection)", async () => {
|
|
385
|
+
return this.find(callback);
|
|
386
|
+
});
|
|
341
387
|
}
|
|
342
388
|
async someAsync(callback) {
|
|
343
|
-
return
|
|
389
|
+
return (0, logExecutionTime_1.logExecutionTime)("someAsync (Collection)", async () => {
|
|
390
|
+
return this.some(callback);
|
|
391
|
+
});
|
|
344
392
|
}
|
|
345
393
|
async everyAsync(callback) {
|
|
346
|
-
return
|
|
394
|
+
return (0, logExecutionTime_1.logExecutionTime)("everyAsync (Collection)", async () => {
|
|
395
|
+
return this.every(callback);
|
|
396
|
+
});
|
|
347
397
|
}
|
|
348
398
|
}
|
|
349
399
|
exports.Queue = Queue;
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RedisQueue = void 0;
|
|
4
4
|
const Manager_1 = require("./Manager");
|
|
5
|
+
const logExecutionTime_1 = require("../utils/logExecutionTime");
|
|
5
6
|
class RedisQueue {
|
|
6
7
|
guildId;
|
|
7
8
|
manager;
|
|
8
|
-
current = null;
|
|
9
|
-
previous = [];
|
|
10
9
|
redis;
|
|
11
10
|
redisPrefix;
|
|
12
11
|
constructor(guildId, manager) {
|
|
@@ -34,268 +33,315 @@ class RedisQueue {
|
|
|
34
33
|
return JSON.parse(data);
|
|
35
34
|
}
|
|
36
35
|
async getCurrent() {
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
return (0, logExecutionTime_1.logExecutionTime)("getCurrent (RedisQueue)", async () => {
|
|
37
|
+
const raw = await this.redis.get(this.currentKey);
|
|
38
|
+
return raw ? this.deserialize(raw) : null;
|
|
39
|
+
});
|
|
39
40
|
}
|
|
40
41
|
async setCurrent(track) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
return (0, logExecutionTime_1.logExecutionTime)("setCurrent (RedisQueue)", async () => {
|
|
43
|
+
if (track) {
|
|
44
|
+
await this.redis.set(this.currentKey, this.serialize(track));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
await this.redis.del(this.currentKey);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
47
50
|
}
|
|
48
51
|
async getPrevious() {
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
return (0, logExecutionTime_1.logExecutionTime)("getPrevious (RedisQueue)", async () => {
|
|
53
|
+
const raw = await this.redis.lrange(this.previousKey, 0, -1);
|
|
54
|
+
return raw.map(this.deserialize);
|
|
55
|
+
});
|
|
51
56
|
}
|
|
52
57
|
async addPrevious(track) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
return (0, logExecutionTime_1.logExecutionTime)("addPrevious (RedisQueue)", async () => {
|
|
59
|
+
const tracks = Array.isArray(track) ? track : [track];
|
|
60
|
+
if (!tracks.length)
|
|
61
|
+
return;
|
|
62
|
+
const serialized = tracks.map(this.serialize);
|
|
63
|
+
if (!serialized.length)
|
|
64
|
+
return; // avoid lpush with no values
|
|
65
|
+
await this.redis.lpush(this.previousKey, ...serialized.reverse());
|
|
66
|
+
});
|
|
60
67
|
}
|
|
61
68
|
async clearPrevious() {
|
|
62
|
-
|
|
69
|
+
return (0, logExecutionTime_1.logExecutionTime)("clearPrevious (RedisQueue)", async () => {
|
|
70
|
+
await this.redis.del(this.previousKey);
|
|
71
|
+
});
|
|
63
72
|
}
|
|
64
73
|
async add(track, offset) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
return (0, logExecutionTime_1.logExecutionTime)("add (RedisQueue)", async () => {
|
|
75
|
+
const isArray = Array.isArray(track);
|
|
76
|
+
const tracks = isArray ? track : [track];
|
|
77
|
+
const serialized = tracks.map((t) => this.serialize(t));
|
|
78
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
79
|
+
// If there's no current track, pop one from the list
|
|
80
|
+
if (!(await this.getCurrent())) {
|
|
81
|
+
const current = serialized.shift();
|
|
82
|
+
if (current) {
|
|
83
|
+
await this.setCurrent(this.deserialize(current));
|
|
84
|
+
}
|
|
75
85
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
86
|
+
if (typeof offset === "number" && !isNaN(offset)) {
|
|
87
|
+
const queue = await this.redis.lrange(this.queueKey, 0, -1);
|
|
88
|
+
queue.splice(offset, 0, ...serialized);
|
|
89
|
+
await this.redis.del(this.queueKey);
|
|
90
|
+
if (queue.length > 0) {
|
|
91
|
+
await this.redis.rpush(this.queueKey, ...queue);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (serialized.length > 0) {
|
|
95
|
+
await this.redis.rpush(this.queueKey, ...serialized);
|
|
83
96
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
return;
|
|
97
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Added ${tracks.length} track(s) to queue`);
|
|
98
|
+
if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
|
|
99
|
+
if (!Array.isArray(track)) {
|
|
100
|
+
const botUser = (await this.manager.players.get(this.guildId).get("Internal_BotUser"));
|
|
101
|
+
if (botUser && botUser.id === track.requester.id) {
|
|
102
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
103
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
104
|
+
details: {
|
|
105
|
+
changeType: "autoPlayAdd",
|
|
106
|
+
tracks: Array.isArray(track) ? track : [track],
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
101
111
|
}
|
|
102
112
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
113
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
114
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
115
|
+
details: {
|
|
116
|
+
changeType: "add",
|
|
117
|
+
tracks,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
110
120
|
});
|
|
111
121
|
}
|
|
112
122
|
async remove(startOrPos = 0, end) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
|
|
123
|
+
return (0, logExecutionTime_1.logExecutionTime)("remove (RedisQueue)", async () => {
|
|
124
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
125
|
+
const queue = await this.redis.lrange(this.queueKey, 0, -1);
|
|
126
|
+
let removed = [];
|
|
127
|
+
if (typeof end === "number") {
|
|
128
|
+
if (startOrPos >= end || startOrPos >= queue.length) {
|
|
129
|
+
throw new RangeError("Invalid range.");
|
|
130
|
+
}
|
|
131
|
+
removed = queue.slice(startOrPos, end);
|
|
132
|
+
queue.splice(startOrPos, end - startOrPos);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
removed = queue.splice(startOrPos, 1);
|
|
136
|
+
}
|
|
137
|
+
await this.redis.del(this.queueKey);
|
|
138
|
+
if (queue.length > 0) {
|
|
139
|
+
await this.redis.rpush(this.queueKey, ...queue);
|
|
119
140
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const deserialized = removed.map(this.deserialize);
|
|
131
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Removed ${removed.length} track(s) from position ${startOrPos}${end ? ` to ${end}` : ""}`);
|
|
132
|
-
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
133
|
-
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
134
|
-
details: {
|
|
135
|
-
changeType: "remove",
|
|
136
|
-
tracks: deserialized,
|
|
137
|
-
},
|
|
141
|
+
const deserialized = removed.map(this.deserialize);
|
|
142
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Removed ${removed.length} track(s) from position ${startOrPos}${end ? ` to ${end}` : ""}`);
|
|
143
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
144
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
145
|
+
details: {
|
|
146
|
+
changeType: "remove",
|
|
147
|
+
tracks: deserialized,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
return deserialized;
|
|
138
151
|
});
|
|
139
|
-
return deserialized;
|
|
140
152
|
}
|
|
141
153
|
async clear() {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
return (0, logExecutionTime_1.logExecutionTime)("clear (RedisQueue)", async () => {
|
|
155
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
156
|
+
await this.redis.del(this.queueKey);
|
|
157
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
158
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
159
|
+
details: {
|
|
160
|
+
changeType: "clear",
|
|
161
|
+
tracks: [],
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Cleared the queue for: ${this.guildId}`);
|
|
150
165
|
});
|
|
151
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Cleared the queue for: ${this.guildId}`);
|
|
152
166
|
}
|
|
153
167
|
async size() {
|
|
154
|
-
return
|
|
168
|
+
return (0, logExecutionTime_1.logExecutionTime)("size (RedisQueue)", async () => {
|
|
169
|
+
return await this.redis.llen(this.queueKey);
|
|
170
|
+
});
|
|
155
171
|
}
|
|
156
172
|
async totalSize() {
|
|
157
|
-
|
|
158
|
-
|
|
173
|
+
return (0, logExecutionTime_1.logExecutionTime)("totalSize (RedisQueue)", async () => {
|
|
174
|
+
const size = await this.size();
|
|
175
|
+
return (await this.getCurrent()) ? size + 1 : size;
|
|
176
|
+
});
|
|
159
177
|
}
|
|
160
178
|
async duration() {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
return (0, logExecutionTime_1.logExecutionTime)("duration (RedisQueue)", async () => {
|
|
180
|
+
const tracks = await this.redis.lrange(this.queueKey, 0, -1);
|
|
181
|
+
const currentDuration = (await this.getCurrent())?.duration || 0;
|
|
182
|
+
const total = tracks.reduce((acc, raw) => {
|
|
183
|
+
try {
|
|
184
|
+
const parsed = this.deserialize(raw);
|
|
185
|
+
return acc + (parsed.duration || 0);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return acc;
|
|
189
|
+
}
|
|
190
|
+
}, currentDuration);
|
|
191
|
+
return total;
|
|
192
|
+
});
|
|
173
193
|
}
|
|
174
194
|
async shuffle() {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
195
|
+
return (0, logExecutionTime_1.logExecutionTime)("shuffle (RedisQueue)", async () => {
|
|
196
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
197
|
+
const queue = await this.redis.lrange(this.queueKey, 0, -1);
|
|
198
|
+
for (let i = queue.length - 1; i > 0; i--) {
|
|
199
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
200
|
+
[queue[i], queue[j]] = [queue[j], queue[i]];
|
|
201
|
+
}
|
|
202
|
+
await this.redis.del(this.queueKey);
|
|
203
|
+
if (queue.length > 0) {
|
|
204
|
+
await this.redis.rpush(this.queueKey, ...queue);
|
|
205
|
+
}
|
|
206
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
207
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
208
|
+
details: { changeType: "shuffle" },
|
|
209
|
+
});
|
|
210
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Shuffled the queue for: ${this.guildId}`);
|
|
188
211
|
});
|
|
189
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] Shuffled the queue for: ${this.guildId}`);
|
|
190
212
|
}
|
|
191
213
|
async userBlockShuffle() {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
userMap.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
214
|
+
return (0, logExecutionTime_1.logExecutionTime)("userBlockShuffle (RedisQueue)", async () => {
|
|
215
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
216
|
+
const rawTracks = await this.redis.lrange(this.queueKey, 0, -1);
|
|
217
|
+
const deserialized = rawTracks.map(this.deserialize);
|
|
218
|
+
const userMap = new Map();
|
|
219
|
+
for (const track of deserialized) {
|
|
220
|
+
const userId = track.requester.id;
|
|
221
|
+
if (!userMap.has(userId))
|
|
222
|
+
userMap.set(userId, []);
|
|
223
|
+
userMap.get(userId).push(track);
|
|
224
|
+
}
|
|
225
|
+
const shuffledQueue = [];
|
|
226
|
+
while (shuffledQueue.length < deserialized.length) {
|
|
227
|
+
for (const [, tracks] of userMap) {
|
|
228
|
+
const track = tracks.shift();
|
|
229
|
+
if (track)
|
|
230
|
+
shuffledQueue.push(track);
|
|
231
|
+
}
|
|
208
232
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
233
|
+
await this.redis.del(this.queueKey);
|
|
234
|
+
await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
|
|
235
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
236
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
237
|
+
details: { changeType: "userBlock" },
|
|
238
|
+
});
|
|
239
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] userBlockShuffled the queue for: ${this.guildId}`);
|
|
215
240
|
});
|
|
216
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] userBlockShuffled the queue for: ${this.guildId}`);
|
|
217
241
|
}
|
|
218
242
|
async roundRobinShuffle() {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
userMap.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
// Shuffle each user's tracks
|
|
230
|
-
for (const tracks of userMap.values()) {
|
|
231
|
-
for (let i = tracks.length - 1; i > 0; i--) {
|
|
232
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
233
|
-
[tracks[i], tracks[j]] = [tracks[j], tracks[i]];
|
|
243
|
+
return (0, logExecutionTime_1.logExecutionTime)("roundRobinShuffle (RedisQueue)", async () => {
|
|
244
|
+
const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
|
|
245
|
+
const rawTracks = await this.redis.lrange(this.queueKey, 0, -1);
|
|
246
|
+
const deserialized = rawTracks.map(this.deserialize);
|
|
247
|
+
const userMap = new Map();
|
|
248
|
+
for (const track of deserialized) {
|
|
249
|
+
const userId = track.requester.id;
|
|
250
|
+
if (!userMap.has(userId))
|
|
251
|
+
userMap.set(userId, []);
|
|
252
|
+
userMap.get(userId).push(track);
|
|
234
253
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const track = q.shift();
|
|
242
|
-
if (track)
|
|
243
|
-
shuffledQueue.push(track);
|
|
254
|
+
// Shuffle each user's tracks
|
|
255
|
+
for (const tracks of userMap.values()) {
|
|
256
|
+
for (let i = tracks.length - 1; i > 0; i--) {
|
|
257
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
258
|
+
[tracks[i], tracks[j]] = [tracks[j], tracks[i]];
|
|
259
|
+
}
|
|
244
260
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
const users = [...userMap.keys()];
|
|
262
|
+
const queues = users.map((id) => userMap.get(id));
|
|
263
|
+
const shuffledQueue = [];
|
|
264
|
+
while (queues.some((q) => q.length > 0)) {
|
|
265
|
+
for (const q of queues) {
|
|
266
|
+
const track = q.shift();
|
|
267
|
+
if (track)
|
|
268
|
+
shuffledQueue.push(track);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
await this.redis.del(this.queueKey);
|
|
272
|
+
await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
|
|
273
|
+
this.manager.emit(Manager_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
|
|
274
|
+
changeType: Manager_1.PlayerStateEventTypes.QueueChange,
|
|
275
|
+
details: { changeType: "roundRobin" },
|
|
276
|
+
});
|
|
277
|
+
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
|
|
251
278
|
});
|
|
252
|
-
this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[QUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
|
|
253
279
|
}
|
|
254
280
|
async dequeue() {
|
|
255
|
-
|
|
256
|
-
|
|
281
|
+
return (0, logExecutionTime_1.logExecutionTime)("dequeue (RedisQueue)", async () => {
|
|
282
|
+
const raw = await this.redis.lpop(this.queueKey);
|
|
283
|
+
return raw ? this.deserialize(raw) : undefined;
|
|
284
|
+
});
|
|
257
285
|
}
|
|
258
286
|
async enqueueFront(track) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
287
|
+
return (0, logExecutionTime_1.logExecutionTime)("enqueueFront (RedisQueue)", async () => {
|
|
288
|
+
const serialized = Array.isArray(track) ? track.map(this.serialize) : [this.serialize(track)];
|
|
289
|
+
// Redis: LPUSH adds to front, reverse to maintain order if multiple tracks
|
|
290
|
+
await this.redis.lpush(this.queueKey, ...serialized.reverse());
|
|
291
|
+
});
|
|
262
292
|
}
|
|
263
293
|
async getTracks() {
|
|
264
|
-
|
|
265
|
-
|
|
294
|
+
return (0, logExecutionTime_1.logExecutionTime)("getTracks (RedisQueue)", async () => {
|
|
295
|
+
const raw = await this.redis.lrange(this.queueKey, 0, -1);
|
|
296
|
+
return raw.map(this.deserialize);
|
|
297
|
+
});
|
|
266
298
|
}
|
|
267
299
|
async getSlice(start = 0, end = -1) {
|
|
268
|
-
|
|
269
|
-
|
|
300
|
+
return (0, logExecutionTime_1.logExecutionTime)("getSlice (RedisQueue)", async () => {
|
|
301
|
+
const raw = await this.redis.lrange(this.queueKey, start, end === -1 ? -1 : end - 1);
|
|
302
|
+
return raw.map(this.deserialize);
|
|
303
|
+
});
|
|
270
304
|
}
|
|
271
305
|
async modifyAt(start, deleteCount = 0, ...items) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
306
|
+
return (0, logExecutionTime_1.logExecutionTime)("modifyAt (RedisQueue)", async () => {
|
|
307
|
+
const queue = await this.redis.lrange(this.queueKey, 0, -1);
|
|
308
|
+
const removed = queue.splice(start, deleteCount, ...items.map(this.serialize));
|
|
309
|
+
await this.redis.del(this.queueKey);
|
|
310
|
+
if (queue.length > 0) {
|
|
311
|
+
await this.redis.rpush(this.queueKey, ...queue);
|
|
312
|
+
}
|
|
313
|
+
return removed.map(this.deserialize);
|
|
314
|
+
});
|
|
279
315
|
}
|
|
280
316
|
async mapAsync(callback) {
|
|
281
|
-
|
|
282
|
-
|
|
317
|
+
return (0, logExecutionTime_1.logExecutionTime)("mapAsync (RedisQueue)", async () => {
|
|
318
|
+
const tracks = await this.getTracks(); // same as lrange + deserialize
|
|
319
|
+
return tracks.map(callback);
|
|
320
|
+
});
|
|
283
321
|
}
|
|
284
322
|
async filterAsync(callback) {
|
|
285
|
-
|
|
286
|
-
|
|
323
|
+
return (0, logExecutionTime_1.logExecutionTime)("filterAsync (RedisQueue)", async () => {
|
|
324
|
+
const tracks = await this.getTracks();
|
|
325
|
+
return tracks.filter(callback);
|
|
326
|
+
});
|
|
287
327
|
}
|
|
288
328
|
async findAsync(callback) {
|
|
289
|
-
|
|
290
|
-
|
|
329
|
+
return (0, logExecutionTime_1.logExecutionTime)("findAsync (RedisQueue)", async () => {
|
|
330
|
+
const tracks = await this.getTracks();
|
|
331
|
+
return tracks.find(callback);
|
|
332
|
+
});
|
|
291
333
|
}
|
|
292
334
|
async someAsync(callback) {
|
|
293
|
-
|
|
294
|
-
|
|
335
|
+
return (0, logExecutionTime_1.logExecutionTime)("someAsync (RedisQueue)", async () => {
|
|
336
|
+
const tracks = await this.getTracks();
|
|
337
|
+
return tracks.some(callback);
|
|
338
|
+
});
|
|
295
339
|
}
|
|
296
340
|
async everyAsync(callback) {
|
|
297
|
-
|
|
298
|
-
|
|
341
|
+
return (0, logExecutionTime_1.logExecutionTime)("everyAsync (RedisQueue)", async () => {
|
|
342
|
+
const tracks = await this.getTracks();
|
|
343
|
+
return tracks.every(callback);
|
|
344
|
+
});
|
|
299
345
|
}
|
|
300
346
|
}
|
|
301
347
|
exports.RedisQueue = RedisQueue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magmastream",
|
|
3
|
-
"version": "2.9.0-dev.
|
|
3
|
+
"version": "2.9.0-dev.12",
|
|
4
4
|
"description": "A user-friendly Lavalink client designed for NodeJS.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -90,4 +90,4 @@
|
|
|
90
90
|
"homepage": "https://docs.magmastream.com",
|
|
91
91
|
"author": "Abel Purnwasy",
|
|
92
92
|
"license": "Apache-2.0"
|
|
93
|
-
}
|
|
93
|
+
}
|