magmastream 2.9.0-dev.42 → 2.9.0-dev.44
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 +205 -164
- package/dist/statestorage/JsonQueue.js +3 -1
- package/dist/structures/Filters.js +5 -5
- package/dist/structures/Manager.js +183 -279
- package/dist/structures/Node.js +1 -1
- package/dist/structures/Rest.js +1 -1
- package/dist/structures/Utils.js +111 -1
- package/package.json +1 -1
|
@@ -49,6 +49,7 @@ class Manager extends events_1.EventEmitter {
|
|
|
49
49
|
// Initialize structures
|
|
50
50
|
Utils_1.Structure.get("Player").init(this);
|
|
51
51
|
Utils_1.TrackUtils.init(this);
|
|
52
|
+
Utils_1.PlayerUtils.init(this);
|
|
52
53
|
if (options.trackPartial) {
|
|
53
54
|
Utils_1.TrackUtils.setTrackPartial(options.trackPartial);
|
|
54
55
|
delete options.trackPartial;
|
|
@@ -264,15 +265,6 @@ class Manager extends events_1.EventEmitter {
|
|
|
264
265
|
getPlayer(guildId) {
|
|
265
266
|
return this.players.get(guildId);
|
|
266
267
|
}
|
|
267
|
-
/**
|
|
268
|
-
* @deprecated - Will be removed with v2.10.0 use {@link getPlayer} instead
|
|
269
|
-
* Returns a player or undefined if it does not exist.
|
|
270
|
-
* @param guildId The guild ID of the player to retrieve.
|
|
271
|
-
* @returns The player if it exists, undefined otherwise.
|
|
272
|
-
*/
|
|
273
|
-
async get(guildId) {
|
|
274
|
-
return this.players.get(guildId);
|
|
275
|
-
}
|
|
276
268
|
/**
|
|
277
269
|
* Creates a player or returns one if it already exists.
|
|
278
270
|
* @param options The options to create the player with.
|
|
@@ -373,7 +365,7 @@ class Manager extends events_1.EventEmitter {
|
|
|
373
365
|
* @returns A promise that resolves to an array of TrackData objects.
|
|
374
366
|
* @throws Will throw an error if no nodes are available or if the API request fails.
|
|
375
367
|
*/
|
|
376
|
-
decodeTracks(tracks) {
|
|
368
|
+
async decodeTracks(tracks) {
|
|
377
369
|
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Decoding tracks: ${JSON.stringify(tracks)}`);
|
|
378
370
|
return new Promise(async (resolve, reject) => {
|
|
379
371
|
const node = this.nodes.first();
|
|
@@ -407,18 +399,18 @@ class Manager extends events_1.EventEmitter {
|
|
|
407
399
|
case Enums_1.StateStorageType.JSON:
|
|
408
400
|
{
|
|
409
401
|
try {
|
|
410
|
-
const playerStateFilePath =
|
|
402
|
+
const playerStateFilePath = Utils_1.PlayerUtils.getPlayerStatePath(guildId);
|
|
411
403
|
const player = this.getPlayer(guildId);
|
|
412
404
|
if (!player || player.state === Enums_1.StateTypes.Disconnected || !player.voiceChannelId) {
|
|
413
|
-
|
|
405
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Skipping save for inactive player: ${guildId}`);
|
|
414
406
|
return;
|
|
415
407
|
}
|
|
416
|
-
const serializedPlayer = await
|
|
408
|
+
const serializedPlayer = await Utils_1.PlayerUtils.serializePlayer(player);
|
|
417
409
|
await promises_1.default.writeFile(playerStateFilePath, JSON.stringify(serializedPlayer, null, 2), "utf-8");
|
|
418
410
|
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved: ${guildId}`);
|
|
419
411
|
}
|
|
420
412
|
catch (error) {
|
|
421
|
-
|
|
413
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error saving player state for guild ${guildId}: ${error}`);
|
|
422
414
|
}
|
|
423
415
|
}
|
|
424
416
|
break;
|
|
@@ -430,7 +422,7 @@ class Manager extends events_1.EventEmitter {
|
|
|
430
422
|
console.warn(`[MANAGER] Skipping save for inactive player: ${guildId}`);
|
|
431
423
|
return;
|
|
432
424
|
}
|
|
433
|
-
const serializedPlayer = await
|
|
425
|
+
const serializedPlayer = await Utils_1.PlayerUtils.serializePlayer(player);
|
|
434
426
|
const redisKey = `${this.options.stateStorage.redisConfig.prefix?.endsWith(":")
|
|
435
427
|
? this.options.stateStorage.redisConfig.prefix
|
|
436
428
|
: this.options.stateStorage.redisConfig.prefix ?? "magmastream:"}playerstore:${guildId}`;
|
|
@@ -438,7 +430,7 @@ class Manager extends events_1.EventEmitter {
|
|
|
438
430
|
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved to Redis: ${guildId}`);
|
|
439
431
|
}
|
|
440
432
|
catch (error) {
|
|
441
|
-
|
|
433
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error saving player state to Redis for guild ${guildId}: ${error}`);
|
|
442
434
|
}
|
|
443
435
|
}
|
|
444
436
|
break;
|
|
@@ -468,196 +460,198 @@ class Manager extends events_1.EventEmitter {
|
|
|
468
460
|
switch (this.options.stateStorage.type) {
|
|
469
461
|
case Enums_1.StateStorageType.JSON:
|
|
470
462
|
{
|
|
471
|
-
const
|
|
463
|
+
const playersBaseDir = Utils_1.PlayerUtils.getPlayersBaseDir();
|
|
472
464
|
try {
|
|
473
|
-
//
|
|
474
|
-
await promises_1.default.access(
|
|
475
|
-
await promises_1.default.mkdir(
|
|
476
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${
|
|
465
|
+
// Ensure base players directory exists
|
|
466
|
+
await promises_1.default.access(playersBaseDir).catch(async () => {
|
|
467
|
+
await promises_1.default.mkdir(playersBaseDir, { recursive: true });
|
|
468
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${playersBaseDir}`);
|
|
477
469
|
});
|
|
478
|
-
// Read
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
470
|
+
// Read guild directories inside players base dir
|
|
471
|
+
const guildDirs = await promises_1.default.readdir(playersBaseDir, { withFileTypes: true });
|
|
472
|
+
for (const dirent of guildDirs) {
|
|
473
|
+
if (!dirent.isDirectory())
|
|
474
|
+
continue;
|
|
475
|
+
const guildId = dirent.name;
|
|
476
|
+
const stateFilePath = Utils_1.PlayerUtils.getPlayerStatePath(guildId);
|
|
483
477
|
try {
|
|
484
|
-
|
|
485
|
-
await promises_1.default.
|
|
486
|
-
const
|
|
487
|
-
const state = JSON.parse(data);
|
|
478
|
+
await promises_1.default.access(stateFilePath);
|
|
479
|
+
const rawData = await promises_1.default.readFile(stateFilePath, "utf-8");
|
|
480
|
+
const state = JSON.parse(rawData);
|
|
488
481
|
if (state.clusterId !== this.options.clusterId)
|
|
489
482
|
continue;
|
|
490
|
-
if (state
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
483
|
+
if (!state.guildId || state.node?.options?.identifier !== nodeId)
|
|
484
|
+
continue;
|
|
485
|
+
const lavaPlayer = info.find((player) => player.guildId === state.guildId);
|
|
486
|
+
if (!lavaPlayer) {
|
|
487
|
+
await this.destroy(state.guildId);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const playerOptions = {
|
|
491
|
+
guildId: state.options.guildId,
|
|
492
|
+
textChannelId: state.options.textChannelId,
|
|
493
|
+
voiceChannelId: state.options.voiceChannelId,
|
|
494
|
+
selfDeafen: state.options.selfDeafen,
|
|
495
|
+
volume: lavaPlayer.volume || state.options.volume,
|
|
496
|
+
nodeIdentifier: nodeId,
|
|
497
|
+
};
|
|
498
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Recreating player: ${state.guildId} from saved file: ${JSON.stringify(state.options)}`);
|
|
499
|
+
const player = this.create(playerOptions);
|
|
500
|
+
await player.node.rest.updatePlayer({
|
|
501
|
+
guildId: state.options.guildId,
|
|
502
|
+
data: {
|
|
503
|
+
voice: {
|
|
504
|
+
token: state.voiceState.event.token,
|
|
505
|
+
endpoint: state.voiceState.event.endpoint,
|
|
506
|
+
sessionId: state.voiceState.sessionId,
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
player.connect();
|
|
511
|
+
const tracks = [];
|
|
512
|
+
const currentTrack = state.queue.current;
|
|
513
|
+
const queueTracks = state.queue.tracks;
|
|
514
|
+
if (state.isAutoplay) {
|
|
515
|
+
Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
|
|
516
|
+
player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
|
|
517
|
+
}
|
|
518
|
+
if (lavaPlayer?.track) {
|
|
519
|
+
tracks.push(...queueTracks);
|
|
520
|
+
if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
|
|
521
|
+
await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
|
|
494
522
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
voiceChannelId: state.options.voiceChannelId,
|
|
499
|
-
selfDeafen: state.options.selfDeafen,
|
|
500
|
-
volume: lavaPlayer.volume || state.options.volume,
|
|
501
|
-
nodeIdentifier: nodeId,
|
|
502
|
-
};
|
|
503
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Recreating player: ${state.guildId} from saved file: ${JSON.stringify(state.options)}`);
|
|
504
|
-
const player = this.create(playerOptions);
|
|
505
|
-
await player.node.rest.updatePlayer({
|
|
506
|
-
guildId: state.options.guildId,
|
|
507
|
-
data: { voice: { token: state.voiceState.event.token, endpoint: state.voiceState.event.endpoint, sessionId: state.voiceState.sessionId } },
|
|
508
|
-
});
|
|
509
|
-
player.connect();
|
|
510
|
-
const tracks = [];
|
|
511
|
-
const currentTrack = state.queue.current;
|
|
512
|
-
const queueTracks = state.queue.tracks;
|
|
513
|
-
if (state.isAutoplay) {
|
|
514
|
-
Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
|
|
515
|
-
player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
|
|
523
|
+
if (tracks.length > 0) {
|
|
524
|
+
await player.queue.clear();
|
|
525
|
+
await player.queue.add(tracks);
|
|
516
526
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
|
|
523
|
-
}
|
|
524
|
-
// Add tracks to queue
|
|
525
|
-
if (tracks.length > 0) {
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
if (currentTrack) {
|
|
530
|
+
if (queueTracks.length > 0) {
|
|
531
|
+
tracks.push(...queueTracks);
|
|
526
532
|
await player.queue.clear();
|
|
527
533
|
await player.queue.add(tracks);
|
|
528
534
|
}
|
|
535
|
+
await node.trackEnd(player, currentTrack, {
|
|
536
|
+
reason: Enums_1.TrackEndReasonTypes.Finished,
|
|
537
|
+
type: "TrackEndEvent",
|
|
538
|
+
});
|
|
529
539
|
}
|
|
530
540
|
else {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
541
|
+
const previousQueue = await player.queue.getPrevious();
|
|
542
|
+
const lastTrack = previousQueue?.at(-1);
|
|
543
|
+
if (lastTrack) {
|
|
544
|
+
if (queueTracks.length === 0) {
|
|
545
|
+
await node.trackEnd(player, lastTrack, {
|
|
546
|
+
reason: Enums_1.TrackEndReasonTypes.Finished,
|
|
547
|
+
type: "TrackEndEvent",
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
534
551
|
tracks.push(...queueTracks);
|
|
552
|
+
if (tracks.length > 0) {
|
|
553
|
+
await player.queue.clear();
|
|
554
|
+
await player.queue.add(tracks);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else if (queueTracks.length > 0) {
|
|
559
|
+
tracks.push(...queueTracks);
|
|
560
|
+
if (tracks.length > 0) {
|
|
535
561
|
await player.queue.clear();
|
|
536
562
|
await player.queue.add(tracks);
|
|
537
563
|
}
|
|
538
|
-
await node.trackEnd(player,
|
|
564
|
+
await node.trackEnd(player, lastTrack, {
|
|
539
565
|
reason: Enums_1.TrackEndReasonTypes.Finished,
|
|
540
566
|
type: "TrackEndEvent",
|
|
541
567
|
});
|
|
542
568
|
}
|
|
543
|
-
else {
|
|
544
|
-
// No current track, check previous queue for last track
|
|
545
|
-
const previousQueue = await player.queue.getPrevious();
|
|
546
|
-
const lastTrack = previousQueue?.at(-1);
|
|
547
|
-
if (lastTrack) {
|
|
548
|
-
if (queueTracks.length === 0) {
|
|
549
|
-
// If no tracks in queue, end last track
|
|
550
|
-
await node.trackEnd(player, lastTrack, {
|
|
551
|
-
reason: Enums_1.TrackEndReasonTypes.Finished,
|
|
552
|
-
type: "TrackEndEvent",
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
else {
|
|
556
|
-
// If there are queued tracks, add them
|
|
557
|
-
tracks.push(...queueTracks);
|
|
558
|
-
if (tracks.length > 0) {
|
|
559
|
-
await player.queue.clear();
|
|
560
|
-
await player.queue.add(tracks);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
if (queueTracks.length > 0) {
|
|
566
|
-
tracks.push(...queueTracks);
|
|
567
|
-
if (tracks.length > 0) {
|
|
568
|
-
await player.queue.clear();
|
|
569
|
-
await player.queue.add(tracks);
|
|
570
|
-
}
|
|
571
|
-
await node.trackEnd(player, lastTrack, {
|
|
572
|
-
reason: Enums_1.TrackEndReasonTypes.Finished,
|
|
573
|
-
type: "TrackEndEvent",
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
if (state.queue.previous.length > 0) {
|
|
580
|
-
await player.queue.addPrevious(state.queue.previous);
|
|
581
|
-
}
|
|
582
|
-
else {
|
|
583
|
-
await player.queue.clearPrevious();
|
|
584
|
-
}
|
|
585
|
-
if (state.paused) {
|
|
586
|
-
await player.pause(true);
|
|
587
|
-
}
|
|
588
|
-
else {
|
|
589
|
-
player.paused = false;
|
|
590
|
-
}
|
|
591
|
-
if (state.trackRepeat)
|
|
592
|
-
player.setTrackRepeat(true);
|
|
593
|
-
if (state.queueRepeat)
|
|
594
|
-
player.setQueueRepeat(true);
|
|
595
|
-
if (state.dynamicRepeat) {
|
|
596
|
-
player.setDynamicRepeat(state.dynamicRepeat, state.dynamicLoopInterval._idleTimeout);
|
|
597
569
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
570
|
+
}
|
|
571
|
+
if (state.queue.previous.length > 0) {
|
|
572
|
+
await player.queue.addPrevious(state.queue.previous);
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
await player.queue.clearPrevious();
|
|
576
|
+
}
|
|
577
|
+
if (state.paused) {
|
|
578
|
+
await player.pause(true);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
player.paused = false;
|
|
582
|
+
}
|
|
583
|
+
if (state.trackRepeat)
|
|
584
|
+
player.setTrackRepeat(true);
|
|
585
|
+
if (state.queueRepeat)
|
|
586
|
+
player.setQueueRepeat(true);
|
|
587
|
+
if (state.dynamicRepeat) {
|
|
588
|
+
player.setDynamicRepeat(state.dynamicRepeat, state.dynamicLoopInterval._idleTimeout);
|
|
589
|
+
}
|
|
590
|
+
if (state.data) {
|
|
591
|
+
for (const [name, value] of Object.entries(state.data)) {
|
|
592
|
+
player.set(name, value);
|
|
602
593
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
594
|
+
}
|
|
595
|
+
const filterActions = {
|
|
596
|
+
bassboost: () => player.filters.bassBoost(state.filters.bassBoostlevel),
|
|
597
|
+
distort: (enabled) => player.filters.distort(enabled),
|
|
598
|
+
setDistortion: () => player.filters.setDistortion(state.filters.distortion),
|
|
599
|
+
eightD: (enabled) => player.filters.eightD(enabled),
|
|
600
|
+
setKaraoke: () => player.filters.setKaraoke(state.filters.karaoke),
|
|
601
|
+
nightcore: (enabled) => player.filters.nightcore(enabled),
|
|
602
|
+
slowmo: (enabled) => player.filters.slowmo(enabled),
|
|
603
|
+
soft: (enabled) => player.filters.soft(enabled),
|
|
604
|
+
trebleBass: (enabled) => player.filters.trebleBass(enabled),
|
|
605
|
+
setTimescale: () => player.filters.setTimescale(state.filters.timescale),
|
|
606
|
+
tv: (enabled) => player.filters.tv(enabled),
|
|
607
|
+
vibrato: () => player.filters.setVibrato(state.filters.vibrato),
|
|
608
|
+
vaporwave: (enabled) => player.filters.vaporwave(enabled),
|
|
609
|
+
pop: (enabled) => player.filters.pop(enabled),
|
|
610
|
+
party: (enabled) => player.filters.party(enabled),
|
|
611
|
+
earrape: (enabled) => player.filters.earrape(enabled),
|
|
612
|
+
electronic: (enabled) => player.filters.electronic(enabled),
|
|
613
|
+
radio: (enabled) => player.filters.radio(enabled),
|
|
614
|
+
setRotation: () => player.filters.setRotation(state.filters.rotation),
|
|
615
|
+
tremolo: (enabled) => player.filters.tremolo(enabled),
|
|
616
|
+
china: (enabled) => player.filters.china(enabled),
|
|
617
|
+
chipmunk: (enabled) => player.filters.chipmunk(enabled),
|
|
618
|
+
darthvader: (enabled) => player.filters.darthvader(enabled),
|
|
619
|
+
daycore: (enabled) => player.filters.daycore(enabled),
|
|
620
|
+
doubletime: (enabled) => player.filters.doubletime(enabled),
|
|
621
|
+
demon: (enabled) => player.filters.demon(enabled),
|
|
622
|
+
};
|
|
623
|
+
for (const [filter, isEnabled] of Object.entries(state.filters.filterStatus)) {
|
|
624
|
+
if (isEnabled && filterActions[filter]) {
|
|
625
|
+
filterActions[filter](true);
|
|
636
626
|
}
|
|
637
|
-
this.emit(Enums_1.ManagerEventTypes.PlayerRestored, player, node);
|
|
638
|
-
await this.sleep(1000);
|
|
639
627
|
}
|
|
628
|
+
this.emit(Enums_1.ManagerEventTypes.PlayerRestored, player, node);
|
|
629
|
+
await this.sleep(1000);
|
|
640
630
|
}
|
|
641
631
|
catch (error) {
|
|
642
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error processing
|
|
643
|
-
continue;
|
|
632
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error processing player state for guild ${guildId}: ${error}`);
|
|
633
|
+
continue;
|
|
644
634
|
}
|
|
645
635
|
}
|
|
646
|
-
//
|
|
647
|
-
for (const
|
|
648
|
-
|
|
636
|
+
// Cleanup old player state files from guild directories whose nodeId matches
|
|
637
|
+
for (const dirent of guildDirs) {
|
|
638
|
+
if (!dirent.isDirectory())
|
|
639
|
+
continue;
|
|
640
|
+
const guildId = dirent.name;
|
|
641
|
+
const stateFilePath = Utils_1.PlayerUtils.getPlayerStatePath(guildId);
|
|
649
642
|
try {
|
|
650
|
-
await promises_1.default.access(
|
|
651
|
-
const data = await promises_1.default.readFile(
|
|
643
|
+
await promises_1.default.access(stateFilePath);
|
|
644
|
+
const data = await promises_1.default.readFile(stateFilePath, "utf-8");
|
|
652
645
|
const state = JSON.parse(data);
|
|
653
|
-
if (state && typeof state === "object" && state.node
|
|
654
|
-
|
|
655
|
-
|
|
646
|
+
if (state && typeof state === "object" && state.node?.options?.identifier === nodeId) {
|
|
647
|
+
// Remove the entire guild directory or just the state file depending on your cleanup strategy
|
|
648
|
+
await promises_1.default.rm(Utils_1.PlayerUtils.getGuildDir(guildId), { recursive: true, force: true });
|
|
649
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted player state folder for guild ${guildId}`);
|
|
656
650
|
}
|
|
657
651
|
}
|
|
658
652
|
catch (error) {
|
|
659
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error deleting
|
|
660
|
-
continue;
|
|
653
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error deleting player state for guild ${guildId}: ${error}`);
|
|
654
|
+
continue;
|
|
661
655
|
}
|
|
662
656
|
}
|
|
663
657
|
}
|
|
@@ -1044,81 +1038,6 @@ class Manager extends events_1.EventEmitter {
|
|
|
1044
1038
|
await player.pause(true);
|
|
1045
1039
|
return;
|
|
1046
1040
|
}
|
|
1047
|
-
/**
|
|
1048
|
-
* Gets each player's JSON file
|
|
1049
|
-
* @param {string} guildId - The guild ID
|
|
1050
|
-
* @returns {string} The path to the player's JSON file
|
|
1051
|
-
*/
|
|
1052
|
-
async getPlayerFilePath(guildId) {
|
|
1053
|
-
const configDir = path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "playerStore");
|
|
1054
|
-
try {
|
|
1055
|
-
await promises_1.default.mkdir(configDir, { recursive: true });
|
|
1056
|
-
return path_1.default.join(configDir, `${guildId}.json`);
|
|
1057
|
-
}
|
|
1058
|
-
catch (err) {
|
|
1059
|
-
console.error(`[MANAGER] Error ensuring player data directory exists: ${err}`);
|
|
1060
|
-
throw new Error(`Failed to resolve player file path for guild ${guildId}`);
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
/**
|
|
1064
|
-
* Serializes a Player instance to avoid circular references.
|
|
1065
|
-
* @param player The Player instance to serialize
|
|
1066
|
-
* @returns The serialized Player instance
|
|
1067
|
-
*/
|
|
1068
|
-
async serializePlayer(player) {
|
|
1069
|
-
const seen = new WeakSet();
|
|
1070
|
-
// Fetch async queue data once before serializing
|
|
1071
|
-
const current = await player.queue.getCurrent();
|
|
1072
|
-
const tracks = Array.isArray(await player.queue.getTracks()) ? await player.queue.getTracks() : [];
|
|
1073
|
-
const previous = Array.isArray(await player.queue.getPrevious()) ? await player.queue.getPrevious() : [];
|
|
1074
|
-
/**
|
|
1075
|
-
* Recursively serializes an object, avoiding circular references.
|
|
1076
|
-
* @param obj The object to serialize
|
|
1077
|
-
* @returns The serialized object
|
|
1078
|
-
*/
|
|
1079
|
-
const serialize = (obj) => {
|
|
1080
|
-
if (obj && typeof obj === "object") {
|
|
1081
|
-
if (seen.has(obj))
|
|
1082
|
-
return;
|
|
1083
|
-
seen.add(obj);
|
|
1084
|
-
}
|
|
1085
|
-
return obj;
|
|
1086
|
-
};
|
|
1087
|
-
return JSON.parse(JSON.stringify(player, (key, value) => {
|
|
1088
|
-
if (key === "manager") {
|
|
1089
|
-
return null;
|
|
1090
|
-
}
|
|
1091
|
-
if (key === "filters") {
|
|
1092
|
-
if (!value || typeof value !== "object")
|
|
1093
|
-
return null;
|
|
1094
|
-
return {
|
|
1095
|
-
distortion: value.distortion ?? null,
|
|
1096
|
-
equalizer: value.equalizer ?? [],
|
|
1097
|
-
karaoke: value.karaoke ?? null,
|
|
1098
|
-
rotation: value.rotation ?? null,
|
|
1099
|
-
timescale: value.timescale ?? null,
|
|
1100
|
-
vibrato: value.vibrato ?? null,
|
|
1101
|
-
reverb: value.reverb ?? null,
|
|
1102
|
-
volume: value.volume ?? 1.0,
|
|
1103
|
-
bassBoostlevel: value.bassBoostlevel ?? null,
|
|
1104
|
-
filterStatus: value.filtersStatus ? { ...value.filtersStatus } : {},
|
|
1105
|
-
};
|
|
1106
|
-
}
|
|
1107
|
-
if (key === "queue") {
|
|
1108
|
-
return {
|
|
1109
|
-
current,
|
|
1110
|
-
tracks,
|
|
1111
|
-
previous,
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
if (key === "data") {
|
|
1115
|
-
return {
|
|
1116
|
-
clientUser: value?.Internal_BotUser ?? null,
|
|
1117
|
-
};
|
|
1118
|
-
}
|
|
1119
|
-
return serialize(value);
|
|
1120
|
-
}));
|
|
1121
|
-
}
|
|
1122
1041
|
/**
|
|
1123
1042
|
* Cleans up inactive players by removing their state files from the file system.
|
|
1124
1043
|
* This is done to prevent stale state files from accumulating on the file system.
|
|
@@ -1127,30 +1046,18 @@ class Manager extends events_1.EventEmitter {
|
|
|
1127
1046
|
switch (this.options.stateStorage.type) {
|
|
1128
1047
|
case Enums_1.StateStorageType.JSON:
|
|
1129
1048
|
{
|
|
1130
|
-
const
|
|
1131
|
-
const playerDataDir = this.options.stateStorage?.jsonConfig?.path ?? path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "players");
|
|
1049
|
+
const playersBaseDir = Utils_1.PlayerUtils.getPlayersBaseDir();
|
|
1132
1050
|
try {
|
|
1133
|
-
await promises_1.default.mkdir(
|
|
1134
|
-
await promises_1.default.mkdir(playerDataDir, { recursive: true });
|
|
1051
|
+
await promises_1.default.mkdir(playersBaseDir, { recursive: true });
|
|
1135
1052
|
const activeGuildIds = new Set(this.players.keys());
|
|
1136
|
-
//
|
|
1137
|
-
const
|
|
1138
|
-
for (const file of playerStateFiles) {
|
|
1139
|
-
const guildId = path_1.default.basename(file, ".json");
|
|
1140
|
-
if (!activeGuildIds.has(guildId)) {
|
|
1141
|
-
const filePath = path_1.default.join(playerStoreDir, file);
|
|
1142
|
-
await promises_1.default.unlink(filePath);
|
|
1143
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted inactive player state: ${guildId}`);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
// Clean up players/<guildId>/ folders
|
|
1147
|
-
const guildDirs = await promises_1.default.readdir(playerDataDir, { withFileTypes: true });
|
|
1053
|
+
// Cleanup inactive guild directories inside playersBaseDir
|
|
1054
|
+
const guildDirs = await promises_1.default.readdir(playersBaseDir, { withFileTypes: true });
|
|
1148
1055
|
for (const dirent of guildDirs) {
|
|
1149
1056
|
if (!dirent.isDirectory())
|
|
1150
1057
|
continue;
|
|
1151
1058
|
const guildId = dirent.name;
|
|
1152
1059
|
if (!activeGuildIds.has(guildId)) {
|
|
1153
|
-
const guildPath =
|
|
1060
|
+
const guildPath = Utils_1.PlayerUtils.getGuildDir(guildId);
|
|
1154
1061
|
await promises_1.default.rm(guildPath, { recursive: true, force: true });
|
|
1155
1062
|
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted inactive player data folder: ${guildId}`);
|
|
1156
1063
|
}
|
|
@@ -1202,13 +1109,11 @@ class Manager extends events_1.EventEmitter {
|
|
|
1202
1109
|
switch (this.options.stateStorage.type) {
|
|
1203
1110
|
case Enums_1.StateStorageType.JSON:
|
|
1204
1111
|
{
|
|
1205
|
-
const playersStoreDir = path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "playerStore");
|
|
1206
|
-
const playersDataDir = this.options.stateStorage?.jsonConfig?.path ?? path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "players");
|
|
1207
1112
|
try {
|
|
1208
1113
|
if (!this.players.has(guildId)) {
|
|
1209
|
-
|
|
1210
|
-
await promises_1.default.rm(
|
|
1211
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER]
|
|
1114
|
+
const guildDir = Utils_1.PlayerUtils.getGuildDir(guildId);
|
|
1115
|
+
await promises_1.default.rm(guildDir, { recursive: true, force: true });
|
|
1116
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted inactive player data folder: ${guildId}`);
|
|
1212
1117
|
}
|
|
1213
1118
|
}
|
|
1214
1119
|
catch (error) {
|
|
@@ -1283,19 +1188,18 @@ class Manager extends events_1.EventEmitter {
|
|
|
1283
1188
|
switch (this.options.stateStorage.type) {
|
|
1284
1189
|
case Enums_1.StateStorageType.Memory:
|
|
1285
1190
|
case Enums_1.StateStorageType.JSON: {
|
|
1286
|
-
const
|
|
1191
|
+
const playersBaseDir = Utils_1.PlayerUtils.getPlayersBaseDir();
|
|
1287
1192
|
try {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${configDir}`);
|
|
1193
|
+
await promises_1.default.access(playersBaseDir).catch(async () => {
|
|
1194
|
+
await promises_1.default.mkdir(playersBaseDir, { recursive: true });
|
|
1195
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${playersBaseDir}`);
|
|
1292
1196
|
});
|
|
1293
|
-
const files = await promises_1.default.readdir(
|
|
1294
|
-
await Promise.all(files.map((file) => promises_1.default.unlink(path_1.default.join(
|
|
1295
|
-
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Cleared all player state files in ${
|
|
1197
|
+
const files = await promises_1.default.readdir(playersBaseDir);
|
|
1198
|
+
await Promise.all(files.map((file) => promises_1.default.unlink(path_1.default.join(playersBaseDir, file)).catch((err) => this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Failed to delete file ${file}: ${err}`))));
|
|
1199
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Cleared all player state files in ${playersBaseDir}`);
|
|
1296
1200
|
}
|
|
1297
1201
|
catch (err) {
|
|
1298
|
-
|
|
1202
|
+
this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error clearing player state files: ${err}`);
|
|
1299
1203
|
}
|
|
1300
1204
|
break;
|
|
1301
1205
|
}
|
package/dist/structures/Node.js
CHANGED
|
@@ -91,7 +91,7 @@ class Node {
|
|
|
91
91
|
this.rest = new Rest_1.Rest(this, this.manager);
|
|
92
92
|
switch (this.manager.options.stateStorage.type) {
|
|
93
93
|
case Enums_1.StateStorageType.JSON:
|
|
94
|
-
this.sessionIdsFilePath = path_1.default.join(process.cwd(), "magmastream", "
|
|
94
|
+
this.sessionIdsFilePath = path_1.default.join(process.cwd(), "magmastream", "sessionData", "sessionIds.json");
|
|
95
95
|
const configDir = path_1.default.dirname(this.sessionIdsFilePath);
|
|
96
96
|
if (!fs_1.default.existsSync(configDir)) {
|
|
97
97
|
fs_1.default.mkdirSync(configDir, { recursive: true });
|
package/dist/structures/Rest.js
CHANGED
|
@@ -50,7 +50,7 @@ class Rest {
|
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* Sends a PATCH request to update player related data.
|
|
53
|
-
* @param {
|
|
53
|
+
* @param {RestPlayOptions} options The options to update the player with.
|
|
54
54
|
* @returns {Promise<unknown>} Returns the result of the PATCH request.
|
|
55
55
|
*/
|
|
56
56
|
async updatePlayer(options) {
|