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