magmastream 2.9.2-dev.1 → 2.9.2-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RedisQueue = void 0;
4
4
  const Enums_1 = require("../structures/Enums");
5
5
  const Utils_1 = require("../structures/Utils");
6
+ const MagmastreamError_1 = require("../structures/MagmastreamError");
6
7
  /**
7
8
  * The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
8
9
  */
@@ -26,9 +27,11 @@ class RedisQueue {
26
27
  this.guildId = guildId;
27
28
  this.manager = manager;
28
29
  this.redis = manager.redis;
29
- this.redisPrefix = manager.options.stateStorage.redisConfig.prefix?.endsWith(":")
30
- ? manager.options.stateStorage.redisConfig.prefix
31
- : `${manager.options.stateStorage.redisConfig.prefix ?? "magmastream"}:`;
30
+ const rawPrefix = manager.options.stateStorage.redisConfig.prefix;
31
+ let clean = typeof rawPrefix === "string" ? rawPrefix.trim() : "";
32
+ if (!clean.endsWith(":"))
33
+ clean = clean || "magmastream";
34
+ this.redisPrefix = `${clean}:`;
32
35
  }
33
36
  // #region Public
34
37
  /**
@@ -37,75 +40,142 @@ class RedisQueue {
37
40
  * @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.
38
41
  */
39
42
  async add(track, offset) {
40
- const isArray = Array.isArray(track);
41
- const tracks = isArray ? track : [track];
42
- const serialized = tracks.map((t) => this.serialize(t));
43
- const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
44
- // If there's no current track, pop one from the list
45
- if (!(await this.getCurrent())) {
46
- const current = serialized.shift();
47
- if (current) {
48
- await this.setCurrent(this.deserialize(current));
43
+ try {
44
+ const isArray = Array.isArray(track);
45
+ const tracks = isArray ? track : [track];
46
+ // Serialize tracks
47
+ const serialized = tracks.map((t) => this.serialize(t));
48
+ const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
49
+ // Set current track if none exists
50
+ if (!(await this.getCurrent())) {
51
+ const current = serialized.shift();
52
+ if (current) {
53
+ await this.setCurrent(this.deserialize(current));
54
+ }
49
55
  }
50
- }
51
- if (typeof offset === "number" && !isNaN(offset)) {
52
- const queue = await this.redis.lrange(this.queueKey, 0, -1);
53
- queue.splice(offset, 0, ...serialized);
54
- await this.redis.del(this.queueKey);
55
- if (queue.length > 0) {
56
- await this.redis.rpush(this.queueKey, ...queue);
56
+ // Insert at offset or append
57
+ try {
58
+ if (typeof offset === "number" && !isNaN(offset)) {
59
+ const queue = await this.redis.lrange(this.queueKey, 0, -1);
60
+ queue.splice(offset, 0, ...serialized);
61
+ await this.redis.del(this.queueKey);
62
+ if (queue.length > 0) {
63
+ await this.redis.rpush(this.queueKey, ...queue);
64
+ }
65
+ }
66
+ else if (serialized.length > 0) {
67
+ await this.redis.rpush(this.queueKey, ...serialized);
68
+ }
57
69
  }
58
- }
59
- else if (serialized.length > 0) {
60
- await this.redis.rpush(this.queueKey, ...serialized);
61
- }
62
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Added ${tracks.length} track(s) to queue`);
63
- if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
64
- if (!Array.isArray(track)) {
65
- const AutoplayUser = (await this.manager.players.get(this.guildId).get("Internal_AutoplayUser"));
66
- if (AutoplayUser && AutoplayUser.id === track.requester.id) {
67
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
68
- changeType: Enums_1.PlayerStateEventTypes.QueueChange,
69
- details: {
70
- type: "queue",
71
- action: "autoPlayAdd",
72
- tracks: Array.isArray(track) ? track : [track],
73
- },
70
+ catch (err) {
71
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
72
+ ? err
73
+ : new MagmastreamError_1.MagmaStreamError({
74
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
75
+ message: `Failed to add tracks to Redis queue for guild ${this.guildId}: ${err.message}`,
76
+ cause: err,
74
77
  });
75
- return;
78
+ console.error(error);
79
+ }
80
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] Added ${tracks.length} track(s) to queue`);
81
+ // Autoplay logic
82
+ if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
83
+ if (!Array.isArray(track)) {
84
+ const AutoplayUser = (await this.manager.players.get(this.guildId).get("Internal_AutoplayUser"));
85
+ if (AutoplayUser && AutoplayUser.id === track.requester.id) {
86
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
87
+ changeType: Enums_1.PlayerStateEventTypes.QueueChange,
88
+ details: {
89
+ type: "queue",
90
+ action: "autoPlayAdd",
91
+ tracks: [track],
92
+ },
93
+ });
94
+ return;
95
+ }
76
96
  }
77
97
  }
98
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
99
+ changeType: Enums_1.PlayerStateEventTypes.QueueChange,
100
+ details: {
101
+ type: "queue",
102
+ action: "add",
103
+ tracks,
104
+ },
105
+ });
106
+ }
107
+ catch (err) {
108
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
109
+ ? err
110
+ : new MagmastreamError_1.MagmaStreamError({
111
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
112
+ message: `Unexpected error in add() for guild ${this.guildId}: ${err.message}`,
113
+ cause: err,
114
+ });
115
+ console.error(error);
78
116
  }
79
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
80
- changeType: Enums_1.PlayerStateEventTypes.QueueChange,
81
- details: {
82
- type: "queue",
83
- action: "add",
84
- tracks,
85
- },
86
- });
87
117
  }
88
118
  /**
89
119
  * Adds a track or tracks to the previous tracks.
90
120
  * @param track The track or tracks to add.
91
121
  */
92
122
  async addPrevious(track) {
93
- const tracks = Array.isArray(track) ? track : [track];
94
- if (!tracks.length)
95
- return;
96
- const serialized = tracks.map(this.serialize);
97
- if (!serialized.length)
98
- return;
99
- await this.redis.lpush(this.previousKey, ...serialized.reverse());
100
- const max = this.manager.options.maxPreviousTracks;
101
- await this.redis.ltrim(this.previousKey, 0, max - 1);
123
+ try {
124
+ const tracks = Array.isArray(track) ? track : [track];
125
+ if (!tracks.length) {
126
+ throw new MagmastreamError_1.MagmaStreamError({
127
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
128
+ message: `No tracks provided for addPrevious in guild ${this.guildId}`,
129
+ });
130
+ }
131
+ const serialized = tracks.map(this.serialize);
132
+ try {
133
+ // Push newest to TAIL
134
+ await this.redis.rpush(this.previousKey, ...serialized);
135
+ // Keep only the most recent maxPreviousTracks (trim from HEAD)
136
+ const max = this.manager.options.maxPreviousTracks;
137
+ await this.redis.ltrim(this.previousKey, -max, -1);
138
+ }
139
+ catch (err) {
140
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
141
+ ? err
142
+ : new MagmastreamError_1.MagmaStreamError({
143
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
144
+ message: `Failed to add previous tracks to Redis for guild ${this.guildId}: ${err.message}`,
145
+ cause: err,
146
+ });
147
+ console.error(error);
148
+ }
149
+ }
150
+ catch (err) {
151
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
152
+ ? err
153
+ : new MagmastreamError_1.MagmaStreamError({
154
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
155
+ message: `Unexpected error in addPrevious() for guild ${this.guildId}: ${err.message}`,
156
+ cause: err,
157
+ });
158
+ console.error(error);
159
+ }
102
160
  }
103
161
  /**
104
162
  * Clears the queue.
105
163
  */
106
164
  async clear() {
107
165
  const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
108
- await this.redis.del(this.queueKey);
166
+ try {
167
+ await this.redis.del(this.queueKey);
168
+ }
169
+ catch (err) {
170
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
171
+ ? err
172
+ : new MagmastreamError_1.MagmaStreamError({
173
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
174
+ message: `Failed to clear queue for guild ${this.guildId}: ${err.message}`,
175
+ cause: err,
176
+ });
177
+ console.error(error);
178
+ }
109
179
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
110
180
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
111
181
  details: {
@@ -114,47 +184,97 @@ class RedisQueue {
114
184
  tracks: [],
115
185
  },
116
186
  });
117
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Cleared the queue for: ${this.guildId}`);
187
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] Cleared the queue for: ${this.guildId}`);
118
188
  }
119
189
  /**
120
190
  * Clears the previous tracks.
121
191
  */
122
192
  async clearPrevious() {
123
- await this.redis.del(this.previousKey);
193
+ try {
194
+ await this.redis.del(this.previousKey);
195
+ }
196
+ catch (err) {
197
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
198
+ ? err
199
+ : new MagmastreamError_1.MagmaStreamError({
200
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
201
+ message: `Failed to clear previous tracks for guild ${this.guildId}: ${err.message}`,
202
+ cause: err,
203
+ });
204
+ console.error(error);
205
+ }
124
206
  }
125
207
  /**
126
208
  * Removes the first track from the queue.
127
209
  */
128
210
  async dequeue() {
129
- const raw = await this.redis.lpop(this.queueKey);
130
- return raw ? this.deserialize(raw) : undefined;
211
+ try {
212
+ const raw = await this.redis.lpop(this.queueKey);
213
+ return raw ? this.deserialize(raw) : undefined;
214
+ }
215
+ catch (err) {
216
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
217
+ ? err
218
+ : new MagmastreamError_1.MagmaStreamError({
219
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
220
+ message: `Failed to dequeue track for guild ${this.guildId}: ${err.message}`,
221
+ cause: err,
222
+ });
223
+ console.error(error);
224
+ }
131
225
  }
132
226
  /**
133
227
  * @returns The total duration of the queue in milliseconds.
134
228
  * This includes the duration of the currently playing track.
135
229
  */
136
230
  async duration() {
137
- const tracks = await this.redis.lrange(this.queueKey, 0, -1);
138
- const currentDuration = (await this.getCurrent())?.duration || 0;
139
- const total = tracks.reduce((acc, raw) => {
140
- try {
141
- const parsed = this.deserialize(raw);
142
- return acc + (parsed.duration || 0);
143
- }
144
- catch {
145
- return acc;
146
- }
147
- }, currentDuration);
148
- return total;
231
+ try {
232
+ const tracks = await this.redis.lrange(this.queueKey, 0, -1);
233
+ const currentDuration = (await this.getCurrent())?.duration || 0;
234
+ const total = tracks.reduce((acc, raw) => {
235
+ try {
236
+ const parsed = this.deserialize(raw);
237
+ return acc + (parsed.duration || 0);
238
+ }
239
+ catch (err) {
240
+ // Skip invalid tracks but log
241
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] Skipping invalid track during duration calculation for guild ${this.guildId}: ${err.message}`);
242
+ return acc;
243
+ }
244
+ }, currentDuration);
245
+ return total;
246
+ }
247
+ catch (err) {
248
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
249
+ ? err
250
+ : new MagmastreamError_1.MagmaStreamError({
251
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
252
+ message: `Failed to calculate total queue duration for guild ${this.guildId}: ${err.message}`,
253
+ cause: err,
254
+ });
255
+ console.error(error);
256
+ }
149
257
  }
150
258
  /**
151
259
  * Adds a track to the front of the queue.
152
260
  * @param track The track or tracks to add.
153
261
  */
154
262
  async enqueueFront(track) {
155
- const serialized = Array.isArray(track) ? track.map(this.serialize) : [this.serialize(track)];
156
- // Redis: LPUSH adds to front, reverse to maintain order if multiple tracks
157
- await this.redis.lpush(this.queueKey, ...serialized.reverse());
263
+ try {
264
+ const serialized = Array.isArray(track) ? track.map(this.serialize) : [this.serialize(track)];
265
+ // Redis: LPUSH adds to front, reverse to maintain order if multiple tracks
266
+ await this.redis.lpush(this.queueKey, ...serialized.reverse());
267
+ }
268
+ catch (err) {
269
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
270
+ ? err
271
+ : new MagmastreamError_1.MagmaStreamError({
272
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
273
+ message: `Failed to enqueue track to front for guild ${this.guildId}: ${err.message}`,
274
+ cause: err,
275
+ });
276
+ console.error(error);
277
+ }
158
278
  }
159
279
  /**
160
280
  * Whether all tracks in the queue match the specified condition.
@@ -187,29 +307,77 @@ class RedisQueue {
187
307
  * @returns The current track.
188
308
  */
189
309
  async getCurrent() {
190
- const raw = await this.redis.get(this.currentKey);
191
- return raw ? this.deserialize(raw) : null;
310
+ try {
311
+ const raw = await this.redis.get(this.currentKey);
312
+ return raw ? this.deserialize(raw) : null;
313
+ }
314
+ catch (err) {
315
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
316
+ ? err
317
+ : new MagmastreamError_1.MagmaStreamError({
318
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
319
+ message: `Failed to get current track for guild ${this.guildId}: ${err.message}`,
320
+ cause: err,
321
+ });
322
+ console.error(error);
323
+ }
192
324
  }
193
325
  /**
194
326
  * @returns The previous tracks.
195
327
  */
196
328
  async getPrevious() {
197
- const raw = await this.redis.lrange(this.previousKey, 0, -1);
198
- return raw.map(this.deserialize);
329
+ try {
330
+ const raw = await this.redis.lrange(this.previousKey, 0, -1);
331
+ return raw.map(this.deserialize);
332
+ }
333
+ catch (err) {
334
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
335
+ ? err
336
+ : new MagmastreamError_1.MagmaStreamError({
337
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
338
+ message: `Failed to get previous tracks for guild ${this.guildId}: ${err.message}`,
339
+ cause: err,
340
+ });
341
+ console.error(error);
342
+ }
199
343
  }
200
344
  /**
201
345
  * @returns The tracks in the queue from the start to the end.
202
346
  */
203
347
  async getSlice(start = 0, end = -1) {
204
- const raw = await this.redis.lrange(this.queueKey, start, end === -1 ? -1 : end - 1);
205
- return raw.map(this.deserialize);
348
+ try {
349
+ const raw = await this.redis.lrange(this.queueKey, start, end === -1 ? -1 : end - 1);
350
+ return raw.map(this.deserialize);
351
+ }
352
+ catch (err) {
353
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
354
+ ? err
355
+ : new MagmastreamError_1.MagmaStreamError({
356
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
357
+ message: `Failed to get slice of queue for guild ${this.guildId}: ${err.message}`,
358
+ cause: err,
359
+ });
360
+ console.error(error);
361
+ }
206
362
  }
207
363
  /**
208
364
  * @returns The tracks in the queue.
209
365
  */
210
366
  async getTracks() {
211
- const raw = await this.redis.lrange(this.queueKey, 0, -1);
212
- return raw.map(this.deserialize);
367
+ try {
368
+ const raw = await this.redis.lrange(this.queueKey, 0, -1);
369
+ return raw.map(this.deserialize);
370
+ }
371
+ catch (err) {
372
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
373
+ ? err
374
+ : new MagmastreamError_1.MagmaStreamError({
375
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
376
+ message: `Failed to get tracks for guild ${this.guildId}: ${err.message}`,
377
+ cause: err,
378
+ });
379
+ console.error(error);
380
+ }
213
381
  }
214
382
  /**
215
383
  * Maps the tracks in the queue.
@@ -227,104 +395,165 @@ class RedisQueue {
227
395
  * @returns The removed tracks.
228
396
  */
229
397
  async modifyAt(start, deleteCount = 0, ...items) {
230
- const queue = await this.redis.lrange(this.queueKey, 0, -1);
231
- const removed = queue.splice(start, deleteCount, ...items.map(this.serialize));
232
- await this.redis.del(this.queueKey);
233
- if (queue.length > 0) {
234
- await this.redis.rpush(this.queueKey, ...queue);
398
+ try {
399
+ const queue = await this.redis.lrange(this.queueKey, 0, -1);
400
+ const removed = queue.splice(start, deleteCount, ...items.map(this.serialize));
401
+ await this.redis.del(this.queueKey);
402
+ if (queue.length > 0) {
403
+ await this.redis.rpush(this.queueKey, ...queue);
404
+ }
405
+ return removed.map(this.deserialize);
406
+ }
407
+ catch (err) {
408
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
409
+ ? err
410
+ : new MagmastreamError_1.MagmaStreamError({
411
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
412
+ message: `Failed to modify queue at index ${start} for guild ${this.guildId}: ${err.message}`,
413
+ cause: err,
414
+ });
415
+ console.error(error);
235
416
  }
236
- return removed.map(this.deserialize);
237
417
  }
238
418
  /**
239
419
  * Removes the newest track.
240
420
  * @returns The newest track.
241
421
  */
242
422
  async popPrevious() {
243
- const raw = await this.redis.lpop(this.previousKey); // get newest track (index 0)
244
- return raw ? this.deserialize(raw) : null;
423
+ try {
424
+ // Pop the newest track from the TAIL
425
+ const raw = await this.redis.rpop(this.previousKey);
426
+ return raw ? this.deserialize(raw) : null;
427
+ }
428
+ catch (err) {
429
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
430
+ ? err
431
+ : new MagmastreamError_1.MagmaStreamError({
432
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
433
+ message: `Failed to pop previous track for guild ${this.guildId}: ${err.message}`,
434
+ cause: err,
435
+ });
436
+ console.error(error);
437
+ }
245
438
  }
246
439
  async remove(startOrPos = 0, end) {
247
- const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
248
- const queue = await this.redis.lrange(this.queueKey, 0, -1);
249
- let removed = [];
250
- if (typeof end === "number") {
251
- if (startOrPos >= end || startOrPos >= queue.length) {
252
- throw new RangeError("Invalid range.");
440
+ try {
441
+ const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
442
+ const queue = await this.redis.lrange(this.queueKey, 0, -1);
443
+ let removed = [];
444
+ if (typeof end === "number") {
445
+ if (startOrPos >= end || startOrPos >= queue.length) {
446
+ throw new RangeError("Invalid range.");
447
+ }
448
+ removed = queue.slice(startOrPos, end);
449
+ queue.splice(startOrPos, end - startOrPos);
253
450
  }
254
- removed = queue.slice(startOrPos, end);
255
- queue.splice(startOrPos, end - startOrPos);
256
- }
257
- else {
258
- removed = queue.splice(startOrPos, 1);
451
+ else {
452
+ removed = queue.splice(startOrPos, 1);
453
+ }
454
+ await this.redis.del(this.queueKey);
455
+ if (queue.length > 0) {
456
+ await this.redis.rpush(this.queueKey, ...queue);
457
+ }
458
+ const deserialized = removed.map(this.deserialize);
459
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] Removed ${removed.length} track(s) from position ${startOrPos}${end ? ` to ${end}` : ""}`);
460
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
461
+ changeType: Enums_1.PlayerStateEventTypes.QueueChange,
462
+ details: {
463
+ type: "queue",
464
+ action: "remove",
465
+ tracks: deserialized,
466
+ },
467
+ });
468
+ return deserialized;
259
469
  }
260
- await this.redis.del(this.queueKey);
261
- if (queue.length > 0) {
262
- await this.redis.rpush(this.queueKey, ...queue);
470
+ catch (err) {
471
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
472
+ ? err
473
+ : new MagmastreamError_1.MagmaStreamError({
474
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
475
+ message: `Failed to remove track for guild ${this.guildId}: ${err.message}`,
476
+ cause: err,
477
+ });
478
+ console.error(error);
263
479
  }
264
- const deserialized = removed.map(this.deserialize);
265
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Removed ${removed.length} track(s) from position ${startOrPos}${end ? ` to ${end}` : ""}`);
266
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
267
- changeType: Enums_1.PlayerStateEventTypes.QueueChange,
268
- details: {
269
- type: "queue",
270
- action: "remove",
271
- tracks: deserialized,
272
- },
273
- });
274
- return deserialized;
275
480
  }
276
481
  /**
277
482
  * Shuffles the queue round-robin style.
278
483
  */
279
484
  async roundRobinShuffle() {
280
- const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
281
- const rawTracks = await this.redis.lrange(this.queueKey, 0, -1);
282
- const deserialized = rawTracks.map(this.deserialize);
283
- const userMap = new Map();
284
- for (const track of deserialized) {
285
- const userId = track.requester.id;
286
- if (!userMap.has(userId))
287
- userMap.set(userId, []);
288
- userMap.get(userId).push(track);
289
- }
290
- // Shuffle each user's tracks
291
- for (const tracks of userMap.values()) {
292
- for (let i = tracks.length - 1; i > 0; i--) {
293
- const j = Math.floor(Math.random() * (i + 1));
294
- [tracks[i], tracks[j]] = [tracks[j], tracks[i]];
485
+ try {
486
+ const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
487
+ const rawTracks = await this.redis.lrange(this.queueKey, 0, -1);
488
+ const deserialized = rawTracks.map(this.deserialize);
489
+ const userMap = new Map();
490
+ for (const track of deserialized) {
491
+ const userId = track.requester.id;
492
+ if (!userMap.has(userId))
493
+ userMap.set(userId, []);
494
+ userMap.get(userId).push(track);
295
495
  }
296
- }
297
- const users = [...userMap.keys()];
298
- const queues = users.map((id) => userMap.get(id));
299
- const shuffledQueue = [];
300
- while (queues.some((q) => q.length > 0)) {
301
- for (const q of queues) {
302
- const track = q.shift();
303
- if (track)
304
- shuffledQueue.push(track);
496
+ // Shuffle each user's tracks
497
+ for (const tracks of userMap.values()) {
498
+ for (let i = tracks.length - 1; i > 0; i--) {
499
+ const j = Math.floor(Math.random() * (i + 1));
500
+ [tracks[i], tracks[j]] = [tracks[j], tracks[i]];
501
+ }
502
+ }
503
+ const users = [...userMap.keys()];
504
+ const queues = users.map((id) => userMap.get(id));
505
+ const shuffledQueue = [];
506
+ while (queues.some((q) => q.length > 0)) {
507
+ for (const q of queues) {
508
+ const track = q.shift();
509
+ if (track)
510
+ shuffledQueue.push(track);
511
+ }
305
512
  }
513
+ await this.redis.del(this.queueKey);
514
+ await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
515
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
516
+ changeType: Enums_1.PlayerStateEventTypes.QueueChange,
517
+ details: {
518
+ type: "queue",
519
+ action: "roundRobin",
520
+ },
521
+ });
522
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
523
+ }
524
+ catch (err) {
525
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
526
+ ? err
527
+ : new MagmastreamError_1.MagmaStreamError({
528
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
529
+ message: `Failed to roundRobinShuffle the queue for guild ${this.guildId}: ${err.message}`,
530
+ cause: err,
531
+ });
532
+ console.error(error);
306
533
  }
307
- await this.redis.del(this.queueKey);
308
- await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
309
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
310
- changeType: Enums_1.PlayerStateEventTypes.QueueChange,
311
- details: {
312
- type: "queue",
313
- action: "roundRobin",
314
- },
315
- });
316
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
317
534
  }
318
535
  /**
319
536
  * Sets the current track.
320
537
  * @param track The track to set.
321
538
  */
322
539
  async setCurrent(track) {
323
- if (track) {
324
- await this.redis.set(this.currentKey, this.serialize(track));
540
+ try {
541
+ if (track) {
542
+ await this.redis.set(this.currentKey, this.serialize(track));
543
+ }
544
+ else {
545
+ await this.redis.del(this.currentKey);
546
+ }
325
547
  }
326
- else {
327
- await this.redis.del(this.currentKey);
548
+ catch (err) {
549
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
550
+ ? err
551
+ : new MagmastreamError_1.MagmaStreamError({
552
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
553
+ message: `Failed to setCurrent the queue for guild ${this.guildId}: ${err.message}`,
554
+ cause: err,
555
+ });
556
+ console.error(error);
328
557
  }
329
558
  }
330
559
  /**
@@ -332,43 +561,79 @@ class RedisQueue {
332
561
  * @param track The track to set.
333
562
  */
334
563
  async setPrevious(track) {
335
- const tracks = Array.isArray(track) ? track : [track];
336
- if (!tracks.length)
337
- return;
338
- await this.redis
339
- .multi()
340
- .del(this.previousKey)
341
- .rpush(this.previousKey, ...tracks.map(this.serialize))
342
- .exec();
564
+ try {
565
+ const tracks = Array.isArray(track) ? track : [track];
566
+ if (!tracks.length)
567
+ return;
568
+ await this.redis
569
+ .multi()
570
+ .del(this.previousKey)
571
+ .rpush(this.previousKey, ...tracks.map(this.serialize))
572
+ .exec();
573
+ }
574
+ catch (err) {
575
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
576
+ ? err
577
+ : new MagmastreamError_1.MagmaStreamError({
578
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
579
+ message: `Failed to setPrevious the queue for guild ${this.guildId}: ${err.message}`,
580
+ cause: err,
581
+ });
582
+ console.error(error);
583
+ }
343
584
  }
344
585
  /**
345
586
  * Shuffles the queue.
346
587
  */
347
588
  async shuffle() {
348
- const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
349
- const queue = await this.redis.lrange(this.queueKey, 0, -1);
350
- for (let i = queue.length - 1; i > 0; i--) {
351
- const j = Math.floor(Math.random() * (i + 1));
352
- [queue[i], queue[j]] = [queue[j], queue[i]];
589
+ try {
590
+ const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
591
+ const queue = await this.redis.lrange(this.queueKey, 0, -1);
592
+ for (let i = queue.length - 1; i > 0; i--) {
593
+ const j = Math.floor(Math.random() * (i + 1));
594
+ [queue[i], queue[j]] = [queue[j], queue[i]];
595
+ }
596
+ await this.redis.del(this.queueKey);
597
+ if (queue.length > 0) {
598
+ await this.redis.rpush(this.queueKey, ...queue);
599
+ }
600
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
601
+ changeType: Enums_1.PlayerStateEventTypes.QueueChange,
602
+ details: {
603
+ type: "queue",
604
+ action: "shuffle",
605
+ },
606
+ });
607
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] Shuffled the queue for: ${this.guildId}`);
353
608
  }
354
- await this.redis.del(this.queueKey);
355
- if (queue.length > 0) {
356
- await this.redis.rpush(this.queueKey, ...queue);
609
+ catch (err) {
610
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
611
+ ? err
612
+ : new MagmastreamError_1.MagmaStreamError({
613
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
614
+ message: `Failed to shuffle the queue for guild ${this.guildId}: ${err.message}`,
615
+ cause: err,
616
+ });
617
+ console.error(error);
357
618
  }
358
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
359
- changeType: Enums_1.PlayerStateEventTypes.QueueChange,
360
- details: {
361
- type: "queue",
362
- action: "shuffle",
363
- },
364
- });
365
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Shuffled the queue for: ${this.guildId}`);
366
619
  }
367
620
  /**
368
621
  * @returns The size of the queue.
369
622
  */
370
623
  async size() {
371
- return await this.redis.llen(this.queueKey);
624
+ try {
625
+ return await this.redis.llen(this.queueKey);
626
+ }
627
+ catch (err) {
628
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
629
+ ? err
630
+ : new MagmastreamError_1.MagmaStreamError({
631
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
632
+ message: `Failed to get the size of the queue for guild ${this.guildId}: ${err.message}`,
633
+ cause: err,
634
+ });
635
+ console.error(error);
636
+ }
372
637
  }
373
638
  /**
374
639
  * @returns Whether any tracks in the queue match the specified condition.
@@ -388,34 +653,46 @@ class RedisQueue {
388
653
  * Shuffles the queue, but keeps the tracks of the same user together.
389
654
  */
390
655
  async userBlockShuffle() {
391
- const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
392
- const rawTracks = await this.redis.lrange(this.queueKey, 0, -1);
393
- const deserialized = rawTracks.map(this.deserialize);
394
- const userMap = new Map();
395
- for (const track of deserialized) {
396
- const userId = track.requester.id;
397
- if (!userMap.has(userId))
398
- userMap.set(userId, []);
399
- userMap.get(userId).push(track);
400
- }
401
- const shuffledQueue = [];
402
- while (shuffledQueue.length < deserialized.length) {
403
- for (const [, tracks] of userMap) {
404
- const track = tracks.shift();
405
- if (track)
406
- shuffledQueue.push(track);
656
+ try {
657
+ const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
658
+ const rawTracks = await this.redis.lrange(this.queueKey, 0, -1);
659
+ const deserialized = rawTracks.map(this.deserialize);
660
+ const userMap = new Map();
661
+ for (const track of deserialized) {
662
+ const userId = track.requester.id;
663
+ if (!userMap.has(userId))
664
+ userMap.set(userId, []);
665
+ userMap.get(userId).push(track);
407
666
  }
667
+ const shuffledQueue = [];
668
+ while (shuffledQueue.length < deserialized.length) {
669
+ for (const [, tracks] of userMap) {
670
+ const track = tracks.shift();
671
+ if (track)
672
+ shuffledQueue.push(track);
673
+ }
674
+ }
675
+ await this.redis.del(this.queueKey);
676
+ await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
677
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
678
+ changeType: Enums_1.PlayerStateEventTypes.QueueChange,
679
+ details: {
680
+ type: "queue",
681
+ action: "userBlock",
682
+ },
683
+ });
684
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REDISQUEUE] userBlockShuffled the queue for: ${this.guildId}`);
685
+ }
686
+ catch (err) {
687
+ const error = err instanceof MagmastreamError_1.MagmaStreamError
688
+ ? err
689
+ : new MagmastreamError_1.MagmaStreamError({
690
+ code: Enums_1.MagmaStreamErrorCode.QUEUE_REDIS_ERROR,
691
+ message: `Failed to userBlockShuffle the queue for guild ${this.guildId}: ${err.message}`,
692
+ cause: err,
693
+ });
694
+ console.error(error);
408
695
  }
409
- await this.redis.del(this.queueKey);
410
- await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
411
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
412
- changeType: Enums_1.PlayerStateEventTypes.QueueChange,
413
- details: {
414
- type: "queue",
415
- action: "userBlock",
416
- },
417
- });
418
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] userBlockShuffled the queue for: ${this.guildId}`);
419
696
  }
420
697
  // #endregion Public
421
698
  // #region Private
@@ -429,7 +706,8 @@ class RedisQueue {
429
706
  * Deserializes a track from a string.
430
707
  */
431
708
  deserialize(data) {
432
- return JSON.parse(data);
709
+ const track = JSON.parse(data);
710
+ return Utils_1.TrackUtils.revive(track);
433
711
  }
434
712
  /**
435
713
  * @returns The previous key.