magmastream 2.9.0-dev.42 → 2.9.0-dev.43

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.
@@ -407,18 +407,18 @@ class Manager extends events_1.EventEmitter {
407
407
  case Enums_1.StateStorageType.JSON:
408
408
  {
409
409
  try {
410
- const playerStateFilePath = await this.getPlayerFilePath(guildId);
410
+ const playerStateFilePath = Utils_1.PlayerUtils.getPlayerStatePath(guildId);
411
411
  const player = this.getPlayer(guildId);
412
412
  if (!player || player.state === Enums_1.StateTypes.Disconnected || !player.voiceChannelId) {
413
- console.warn(`[MANAGER] Skipping save for inactive player: ${guildId}`);
413
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Skipping save for inactive player: ${guildId}`);
414
414
  return;
415
415
  }
416
- const serializedPlayer = await this.serializePlayer(player);
416
+ const serializedPlayer = await Utils_1.PlayerUtils.serializePlayer(player);
417
417
  await promises_1.default.writeFile(playerStateFilePath, JSON.stringify(serializedPlayer, null, 2), "utf-8");
418
418
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved: ${guildId}`);
419
419
  }
420
420
  catch (error) {
421
- console.error(`[MANAGER] Error saving player state for guild ${guildId}:`, error);
421
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error saving player state for guild ${guildId}: ${error}`);
422
422
  }
423
423
  }
424
424
  break;
@@ -430,7 +430,7 @@ class Manager extends events_1.EventEmitter {
430
430
  console.warn(`[MANAGER] Skipping save for inactive player: ${guildId}`);
431
431
  return;
432
432
  }
433
- const serializedPlayer = await this.serializePlayer(player);
433
+ const serializedPlayer = await Utils_1.PlayerUtils.serializePlayer(player);
434
434
  const redisKey = `${this.options.stateStorage.redisConfig.prefix?.endsWith(":")
435
435
  ? this.options.stateStorage.redisConfig.prefix
436
436
  : this.options.stateStorage.redisConfig.prefix ?? "magmastream:"}playerstore:${guildId}`;
@@ -438,7 +438,7 @@ class Manager extends events_1.EventEmitter {
438
438
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved to Redis: ${guildId}`);
439
439
  }
440
440
  catch (error) {
441
- console.error(`[MANAGER] Error saving player state to Redis for guild ${guildId}:`, error);
441
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error saving player state to Redis for guild ${guildId}: ${error}`);
442
442
  }
443
443
  }
444
444
  break;
@@ -468,196 +468,198 @@ class Manager extends events_1.EventEmitter {
468
468
  switch (this.options.stateStorage.type) {
469
469
  case Enums_1.StateStorageType.JSON:
470
470
  {
471
- const playerStatesDir = path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "playerStore");
471
+ const playersBaseDir = Utils_1.PlayerUtils.getPlayersBaseDir();
472
472
  try {
473
- // Check if the directory exists, and create it if it doesn't
474
- await promises_1.default.access(playerStatesDir).catch(async () => {
475
- await promises_1.default.mkdir(playerStatesDir, { recursive: true });
476
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${playerStatesDir}`);
473
+ // Ensure base players directory exists
474
+ await promises_1.default.access(playersBaseDir).catch(async () => {
475
+ await promises_1.default.mkdir(playersBaseDir, { recursive: true });
476
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${playersBaseDir}`);
477
477
  });
478
- // Read the contents of the directory
479
- const playerFiles = await promises_1.default.readdir(playerStatesDir);
480
- // Process each file in the directory
481
- for (const file of playerFiles) {
482
- const filePath = path_1.default.join(playerStatesDir, file);
478
+ // Read guild directories inside players base dir
479
+ const guildDirs = await promises_1.default.readdir(playersBaseDir, { withFileTypes: true });
480
+ for (const dirent of guildDirs) {
481
+ if (!dirent.isDirectory())
482
+ continue;
483
+ const guildId = dirent.name;
484
+ const stateFilePath = Utils_1.PlayerUtils.getPlayerStatePath(guildId);
483
485
  try {
484
- // Check if the file exists (though readdir should only return valid files)
485
- await promises_1.default.access(filePath); // Check if the file exists
486
- const data = await promises_1.default.readFile(filePath, "utf-8");
487
- const state = JSON.parse(data);
486
+ await promises_1.default.access(stateFilePath);
487
+ const rawData = await promises_1.default.readFile(stateFilePath, "utf-8");
488
+ const state = JSON.parse(rawData);
488
489
  if (state.clusterId !== this.options.clusterId)
489
490
  continue;
490
- if (state && typeof state === "object" && state.guildId && state.node.options.identifier === nodeId) {
491
- const lavaPlayer = info.find((player) => player.guildId === state.guildId);
492
- if (!lavaPlayer) {
493
- await this.destroy(state.guildId);
491
+ if (!state.guildId || state.node?.options?.identifier !== nodeId)
492
+ continue;
493
+ const lavaPlayer = info.find((player) => player.guildId === state.guildId);
494
+ if (!lavaPlayer) {
495
+ await this.destroy(state.guildId);
496
+ continue;
497
+ }
498
+ const playerOptions = {
499
+ guildId: state.options.guildId,
500
+ textChannelId: state.options.textChannelId,
501
+ voiceChannelId: state.options.voiceChannelId,
502
+ selfDeafen: state.options.selfDeafen,
503
+ volume: lavaPlayer.volume || state.options.volume,
504
+ nodeIdentifier: nodeId,
505
+ };
506
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Recreating player: ${state.guildId} from saved file: ${JSON.stringify(state.options)}`);
507
+ const player = this.create(playerOptions);
508
+ await player.node.rest.updatePlayer({
509
+ guildId: state.options.guildId,
510
+ data: {
511
+ voice: {
512
+ token: state.voiceState.event.token,
513
+ endpoint: state.voiceState.event.endpoint,
514
+ sessionId: state.voiceState.sessionId,
515
+ },
516
+ },
517
+ });
518
+ player.connect();
519
+ const tracks = [];
520
+ const currentTrack = state.queue.current;
521
+ const queueTracks = state.queue.tracks;
522
+ if (state.isAutoplay) {
523
+ Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
524
+ player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
525
+ }
526
+ if (lavaPlayer?.track) {
527
+ tracks.push(...queueTracks);
528
+ if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
529
+ await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
494
530
  }
495
- const playerOptions = {
496
- guildId: state.options.guildId,
497
- textChannelId: state.options.textChannelId,
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);
531
+ if (tracks.length > 0) {
532
+ await player.queue.clear();
533
+ await player.queue.add(tracks);
516
534
  }
517
- if (lavaPlayer?.track) {
518
- // If lavaPlayer has a track, push all queue tracks
519
- tracks.push(...queueTracks);
520
- // Set current track if matches lavaPlayer's track URI
521
- if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
522
- await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
523
- }
524
- // Add tracks to queue
525
- if (tracks.length > 0) {
535
+ }
536
+ else {
537
+ if (currentTrack) {
538
+ if (queueTracks.length > 0) {
539
+ tracks.push(...queueTracks);
526
540
  await player.queue.clear();
527
541
  await player.queue.add(tracks);
528
542
  }
543
+ await node.trackEnd(player, currentTrack, {
544
+ reason: Enums_1.TrackEndReasonTypes.Finished,
545
+ type: "TrackEndEvent",
546
+ });
529
547
  }
530
548
  else {
531
- // LavaPlayer missing track or lavaPlayer is falsy
532
- if (currentTrack) {
533
- if (queueTracks.length > 0) {
549
+ const previousQueue = await player.queue.getPrevious();
550
+ const lastTrack = previousQueue?.at(-1);
551
+ if (lastTrack) {
552
+ if (queueTracks.length === 0) {
553
+ await node.trackEnd(player, lastTrack, {
554
+ reason: Enums_1.TrackEndReasonTypes.Finished,
555
+ type: "TrackEndEvent",
556
+ });
557
+ }
558
+ else {
534
559
  tracks.push(...queueTracks);
560
+ if (tracks.length > 0) {
561
+ await player.queue.clear();
562
+ await player.queue.add(tracks);
563
+ }
564
+ }
565
+ }
566
+ else if (queueTracks.length > 0) {
567
+ tracks.push(...queueTracks);
568
+ if (tracks.length > 0) {
535
569
  await player.queue.clear();
536
570
  await player.queue.add(tracks);
537
571
  }
538
- await node.trackEnd(player, currentTrack, {
572
+ await node.trackEnd(player, lastTrack, {
539
573
  reason: Enums_1.TrackEndReasonTypes.Finished,
540
574
  type: "TrackEndEvent",
541
575
  });
542
576
  }
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
577
  }
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
- }
598
- if (state.data) {
599
- for (const [name, value] of Object.entries(state.data)) {
600
- player.set(name, value);
601
- }
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
+ }
598
+ if (state.data) {
599
+ for (const [name, value] of Object.entries(state.data)) {
600
+ player.set(name, value);
602
601
  }
603
- const filterActions = {
604
- bassboost: () => player.filters.bassBoost(state.filters.bassBoostlevel),
605
- distort: (enabled) => player.filters.distort(enabled),
606
- setDistortion: () => player.filters.setDistortion(state.filters.distortion),
607
- eightD: (enabled) => player.filters.eightD(enabled),
608
- setKaraoke: () => player.filters.setKaraoke(state.filters.karaoke),
609
- nightcore: (enabled) => player.filters.nightcore(enabled),
610
- slowmo: (enabled) => player.filters.slowmo(enabled),
611
- soft: (enabled) => player.filters.soft(enabled),
612
- trebleBass: (enabled) => player.filters.trebleBass(enabled),
613
- setTimescale: () => player.filters.setTimescale(state.filters.timescale),
614
- tv: (enabled) => player.filters.tv(enabled),
615
- vibrato: () => player.filters.setVibrato(state.filters.vibrato),
616
- vaporwave: (enabled) => player.filters.vaporwave(enabled),
617
- pop: (enabled) => player.filters.pop(enabled),
618
- party: (enabled) => player.filters.party(enabled),
619
- earrape: (enabled) => player.filters.earrape(enabled),
620
- electronic: (enabled) => player.filters.electronic(enabled),
621
- radio: (enabled) => player.filters.radio(enabled),
622
- setRotation: () => player.filters.setRotation(state.filters.rotation),
623
- tremolo: (enabled) => player.filters.tremolo(enabled),
624
- china: (enabled) => player.filters.china(enabled),
625
- chipmunk: (enabled) => player.filters.chipmunk(enabled),
626
- darthvader: (enabled) => player.filters.darthvader(enabled),
627
- daycore: (enabled) => player.filters.daycore(enabled),
628
- doubletime: (enabled) => player.filters.doubletime(enabled),
629
- demon: (enabled) => player.filters.demon(enabled),
630
- };
631
- // Iterate through filterStatus and apply the enabled filters
632
- for (const [filter, isEnabled] of Object.entries(state.filters.filterStatus)) {
633
- if (isEnabled && filterActions[filter]) {
634
- filterActions[filter](true);
635
- }
602
+ }
603
+ const filterActions = {
604
+ bassboost: () => player.filters.bassBoost(state.filters.bassBoostlevel),
605
+ distort: (enabled) => player.filters.distort(enabled),
606
+ setDistortion: () => player.filters.setDistortion(state.filters.distortion),
607
+ eightD: (enabled) => player.filters.eightD(enabled),
608
+ setKaraoke: () => player.filters.setKaraoke(state.filters.karaoke),
609
+ nightcore: (enabled) => player.filters.nightcore(enabled),
610
+ slowmo: (enabled) => player.filters.slowmo(enabled),
611
+ soft: (enabled) => player.filters.soft(enabled),
612
+ trebleBass: (enabled) => player.filters.trebleBass(enabled),
613
+ setTimescale: () => player.filters.setTimescale(state.filters.timescale),
614
+ tv: (enabled) => player.filters.tv(enabled),
615
+ vibrato: () => player.filters.setVibrato(state.filters.vibrato),
616
+ vaporwave: (enabled) => player.filters.vaporwave(enabled),
617
+ pop: (enabled) => player.filters.pop(enabled),
618
+ party: (enabled) => player.filters.party(enabled),
619
+ earrape: (enabled) => player.filters.earrape(enabled),
620
+ electronic: (enabled) => player.filters.electronic(enabled),
621
+ radio: (enabled) => player.filters.radio(enabled),
622
+ setRotation: () => player.filters.setRotation(state.filters.rotation),
623
+ tremolo: (enabled) => player.filters.tremolo(enabled),
624
+ china: (enabled) => player.filters.china(enabled),
625
+ chipmunk: (enabled) => player.filters.chipmunk(enabled),
626
+ darthvader: (enabled) => player.filters.darthvader(enabled),
627
+ daycore: (enabled) => player.filters.daycore(enabled),
628
+ doubletime: (enabled) => player.filters.doubletime(enabled),
629
+ demon: (enabled) => player.filters.demon(enabled),
630
+ };
631
+ for (const [filter, isEnabled] of Object.entries(state.filters.filterStatus)) {
632
+ if (isEnabled && filterActions[filter]) {
633
+ filterActions[filter](true);
636
634
  }
637
- this.emit(Enums_1.ManagerEventTypes.PlayerRestored, player, node);
638
- await this.sleep(1000);
639
635
  }
636
+ this.emit(Enums_1.ManagerEventTypes.PlayerRestored, player, node);
637
+ await this.sleep(1000);
640
638
  }
641
639
  catch (error) {
642
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error processing file ${filePath}: ${error}`);
643
- continue; // Skip to the next file if there's an error
640
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error processing player state for guild ${guildId}: ${error}`);
641
+ continue;
644
642
  }
645
643
  }
646
- // Delete all files inside playerStatesDir where nodeId matches
647
- for (const file of playerFiles) {
648
- const filePath = path_1.default.join(playerStatesDir, file);
644
+ // Cleanup old player state files from guild directories whose nodeId matches
645
+ for (const dirent of guildDirs) {
646
+ if (!dirent.isDirectory())
647
+ continue;
648
+ const guildId = dirent.name;
649
+ const stateFilePath = Utils_1.PlayerUtils.getPlayerStatePath(guildId);
649
650
  try {
650
- await promises_1.default.access(filePath); // Check if the file exists
651
- const data = await promises_1.default.readFile(filePath, "utf-8");
651
+ await promises_1.default.access(stateFilePath);
652
+ const data = await promises_1.default.readFile(stateFilePath, "utf-8");
652
653
  const state = JSON.parse(data);
653
- if (state && typeof state === "object" && state.node.options.identifier === nodeId) {
654
- await promises_1.default.unlink(filePath); // Delete the file asynchronously
655
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted player state file: ${filePath}`);
654
+ if (state && typeof state === "object" && state.node?.options?.identifier === nodeId) {
655
+ // Remove the entire guild directory or just the state file depending on your cleanup strategy
656
+ await promises_1.default.rm(Utils_1.PlayerUtils.getGuildDir(guildId), { recursive: true, force: true });
657
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted player state folder for guild ${guildId}`);
656
658
  }
657
659
  }
658
660
  catch (error) {
659
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error deleting file ${filePath}: ${error}`);
660
- continue; // Skip to the next file if there's an error
661
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error deleting player state for guild ${guildId}: ${error}`);
662
+ continue;
661
663
  }
662
664
  }
663
665
  }
@@ -1044,81 +1046,6 @@ class Manager extends events_1.EventEmitter {
1044
1046
  await player.pause(true);
1045
1047
  return;
1046
1048
  }
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
1049
  /**
1123
1050
  * Cleans up inactive players by removing their state files from the file system.
1124
1051
  * This is done to prevent stale state files from accumulating on the file system.
@@ -1127,30 +1054,18 @@ class Manager extends events_1.EventEmitter {
1127
1054
  switch (this.options.stateStorage.type) {
1128
1055
  case Enums_1.StateStorageType.JSON:
1129
1056
  {
1130
- const playerStoreDir = path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "playerStore");
1131
- const playerDataDir = this.options.stateStorage?.jsonConfig?.path ?? path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "players");
1057
+ const playersBaseDir = Utils_1.PlayerUtils.getPlayersBaseDir();
1132
1058
  try {
1133
- await promises_1.default.mkdir(playerStoreDir, { recursive: true });
1134
- await promises_1.default.mkdir(playerDataDir, { recursive: true });
1059
+ await promises_1.default.mkdir(playersBaseDir, { recursive: true });
1135
1060
  const activeGuildIds = new Set(this.players.keys());
1136
- // Clean up playerStore/*.json
1137
- const playerStateFiles = await promises_1.default.readdir(playerStoreDir);
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 });
1061
+ // Cleanup inactive guild directories inside playersBaseDir
1062
+ const guildDirs = await promises_1.default.readdir(playersBaseDir, { withFileTypes: true });
1148
1063
  for (const dirent of guildDirs) {
1149
1064
  if (!dirent.isDirectory())
1150
1065
  continue;
1151
1066
  const guildId = dirent.name;
1152
1067
  if (!activeGuildIds.has(guildId)) {
1153
- const guildPath = path_1.default.join(playerDataDir, guildId);
1068
+ const guildPath = Utils_1.PlayerUtils.getGuildDir(guildId);
1154
1069
  await promises_1.default.rm(guildPath, { recursive: true, force: true });
1155
1070
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted inactive player data folder: ${guildId}`);
1156
1071
  }
@@ -1202,13 +1117,11 @@ class Manager extends events_1.EventEmitter {
1202
1117
  switch (this.options.stateStorage.type) {
1203
1118
  case Enums_1.StateStorageType.JSON:
1204
1119
  {
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
1120
  try {
1208
1121
  if (!this.players.has(guildId)) {
1209
- await promises_1.default.unlink(path_1.default.join(playersStoreDir, `${guildId}.json`));
1210
- await promises_1.default.rm(path_1.default.join(playersDataDir, guildId), { recursive: true, force: true });
1211
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleting inactive player files: ${guildId}`);
1122
+ const guildDir = Utils_1.PlayerUtils.getGuildDir(guildId);
1123
+ await promises_1.default.rm(guildDir, { recursive: true, force: true });
1124
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Deleted inactive player data folder: ${guildId}`);
1212
1125
  }
1213
1126
  }
1214
1127
  catch (error) {
@@ -1283,19 +1196,18 @@ class Manager extends events_1.EventEmitter {
1283
1196
  switch (this.options.stateStorage.type) {
1284
1197
  case Enums_1.StateStorageType.Memory:
1285
1198
  case Enums_1.StateStorageType.JSON: {
1286
- const configDir = path_1.default.join(process.cwd(), "magmastream", "dist", "sessionData", "playerStore");
1199
+ const playersBaseDir = Utils_1.PlayerUtils.getPlayersBaseDir();
1287
1200
  try {
1288
- // Check if the directory exists, and create it if it doesn't
1289
- await promises_1.default.access(configDir).catch(async () => {
1290
- await promises_1.default.mkdir(configDir, { recursive: true });
1291
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${configDir}`);
1201
+ await promises_1.default.access(playersBaseDir).catch(async () => {
1202
+ await promises_1.default.mkdir(playersBaseDir, { recursive: true });
1203
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Created directory: ${playersBaseDir}`);
1292
1204
  });
1293
- const files = await promises_1.default.readdir(configDir);
1294
- await Promise.all(files.map((file) => promises_1.default.unlink(path_1.default.join(configDir, file)).catch((err) => console.warn(`[MANAGER] Failed to delete file ${file}:`, err))));
1295
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Cleared all player state files in ${configDir}`);
1205
+ const files = await promises_1.default.readdir(playersBaseDir);
1206
+ 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}`))));
1207
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Cleared all player state files in ${playersBaseDir}`);
1296
1208
  }
1297
1209
  catch (err) {
1298
- console.error("[MANAGER] Error clearing player state files:", err);
1210
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Error clearing player state files: ${err}`);
1299
1211
  }
1300
1212
  break;
1301
1213
  }
@@ -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", "dist", "sessionData", "sessionIds.json");
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 });
@@ -50,7 +50,7 @@ class Rest {
50
50
  }
51
51
  /**
52
52
  * Sends a PATCH request to update player related data.
53
- * @param {playOptions} options The options to update the player with.
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) {