magmastream 2.9.3-dev.17 → 2.9.3-dev.19

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
@@ -1308,11 +1308,7 @@ interface LavaPlayer {
1308
1308
  connected: boolean;
1309
1309
  ping: number;
1310
1310
  };
1311
- voice: {
1312
- token: string;
1313
- endpoint: string;
1314
- sessionId: string;
1315
- };
1311
+ voice: LavalinkVoiceStateResponse;
1316
1312
  filters: Record<string, unknown>;
1317
1313
  }
1318
1314
  /**
@@ -1917,16 +1913,29 @@ interface RestPlayOptions {
1917
1913
  /** The audio effects. */
1918
1914
  filters?: object;
1919
1915
  /** voice payload. */
1920
- voice?: {
1921
- token: string;
1922
- sessionId: string;
1923
- endpoint: string;
1924
- channelId: string;
1925
- };
1916
+ voice?: LavalinkVoiceStateUpdate;
1926
1917
  /** Whether to not replace the track if a play payload is sent. */
1927
1918
  noReplace?: boolean;
1928
1919
  };
1929
1920
  }
1921
+ /**
1922
+ * Lavalink voice state response
1923
+ */
1924
+ type LavalinkVoiceStateResponse = {
1925
+ token: string;
1926
+ endpoint: string;
1927
+ sessionId: string;
1928
+ channelId: string | null;
1929
+ };
1930
+ /**
1931
+ * Lavalink voice state update
1932
+ */
1933
+ type LavalinkVoiceStateUpdate = {
1934
+ token: string;
1935
+ endpoint: string;
1936
+ sessionId: string;
1937
+ channelId: string;
1938
+ };
1930
1939
  /**
1931
1940
  * ManagerInitOptions interface
1932
1941
  */
@@ -2539,6 +2548,10 @@ declare class Node {
2539
2548
  get connected(): boolean;
2540
2549
  /** Returns the full address for this node, including the host and port. */
2541
2550
  get address(): string;
2551
+ private getCompositeKey;
2552
+ private getRedisSessionIdsKey;
2553
+ private getNodeSessionsDir;
2554
+ private getNodeSessionPath;
2542
2555
  /**
2543
2556
  * Creates the sessionIds.json file if it doesn't exist. This file is used to
2544
2557
  * store the session IDs for each node. The session IDs are used to identify
@@ -2566,6 +2579,8 @@ declare class Node {
2566
2579
  * be used with the same node identifier.
2567
2580
  */
2568
2581
  updateSessionId(): Promise<void>;
2582
+ private updateSessionIdFile;
2583
+ private updateSessionIdRedis;
2569
2584
  /**
2570
2585
  * Connects to the Node.
2571
2586
  *
@@ -3626,6 +3641,10 @@ declare abstract class PlayerUtils {
3626
3641
  * Gets the path to the player's previous tracks file.
3627
3642
  */
3628
3643
  static getPlayerPreviousPath(guildId: string): string;
3644
+ /**
3645
+ * Gets the Redis key for player storage.
3646
+ */
3647
+ static getRedisKey(): string;
3629
3648
  }
3630
3649
  /** Gets or extends structures to extend the built in, or already extended, classes to add more functionality. */
3631
3650
  declare abstract class Structure {
@@ -3736,4 +3755,4 @@ declare class SeyfertManager extends Manager {
3736
3755
  }
3737
3756
 
3738
3757
  export { AutoPlayPlatform, AutoPlayUtils, AvailableFilters, DiscordJSManager, DiscordenoManager, ErisManager, Filters, JSONUtils, JsonQueue, LoadTypes, MagmaStreamError, MagmaStreamErrorCode, MagmaStreamErrorNumbers, Manager, ManagerEventTypes, MemoryQueue, Node, OceanicManager, Player, PlayerStateEventTypes, PlayerUtils, Plugin, RedisQueue, Rest, SearchPlatform, SeverityTypes, SeyfertManager, SponsorBlockSegment, StateStorageType, StateTypes, Structure, TrackEndReasonTypes, TrackPartial, TrackSourceTypes, TrackUtils, UseNodeOptions };
3739
- export type { AlbumSearchResult, AnyMessage, AnyUser, ArtistSearchResult, CPUStats, DiscordPacket, DistortionOptions, EndSpeakingEventVoiceReceiver, EndSpeakingEventVoiceReceiverData, EqualizerBand, ErrorOrEmptySearchResult, Exception, Extendable, FrameStats, IQueue, JsonConfig, KaraokeOptions, LavaPlayer, LavalinkInfo, LavalinkResponse, LoadType, Lyrics, LyricsEvent, LyricsEventType, LyricsFoundEvent, LyricsLine, LyricsLineEvent, LyricsNotFoundEvent, ManagerEvents, ManagerInitOptions, ManagerOptions, MemoryStats, NodeLinkGetLyrics, NodeLinkGetLyricsEmpty, NodeLinkGetLyricsError, NodeLinkGetLyricsMultiple, NodeLinkGetLyricsSingle, NodeMessage, NodeOptions, NodeStats, PlayOptions, PlayerEvent, PlayerEventType, PlayerEvents, PlayerOptions, PlayerStateUpdateEvent, PlayerUpdateVoiceState, PlaylistData, PlaylistInfoData, PlaylistRawData, PlaylistSearchResult, PodcastSearchResult, PortableMessage, PortableUser, RedisConfig, RestPlayOptions, ReverbOptions, RotationOptions, SearchQuery, SearchResult, SearchSearchResult, Severity, ShortSearchResult, ShowSearchResult, Sizes, SponsorBlockChapterStarted, SponsorBlockChaptersLoaded, SponsorBlockSegmentEventType, SponsorBlockSegmentEvents, SponsorBlockSegmentSkipped, SponsorBlockSegmentsLoaded, StartSpeakingEventVoiceReceiver, StartSpeakingEventVoiceReceiverData, StateStorageOptions, StationSearchResult, TimescaleOptions, Track, TrackData, TrackDataInfo, TrackEndEvent, TrackEndReason, TrackExceptionEvent, TrackPluginInfo, TrackSearchResult, TrackSourceName, TrackStartEvent, TrackStuckEvent, UseNodeOption, VibratoOptions, VoicePacket, VoiceReceiverEvent, VoiceServer, VoiceServerUpdate, VoiceState, WebSocketClosedEvent };
3758
+ export type { AlbumSearchResult, AnyMessage, AnyUser, ArtistSearchResult, CPUStats, DiscordPacket, DistortionOptions, EndSpeakingEventVoiceReceiver, EndSpeakingEventVoiceReceiverData, EqualizerBand, ErrorOrEmptySearchResult, Exception, Extendable, FrameStats, IQueue, JsonConfig, KaraokeOptions, LavaPlayer, LavalinkInfo, LavalinkResponse, LavalinkVoiceStateResponse, LavalinkVoiceStateUpdate, LoadType, Lyrics, LyricsEvent, LyricsEventType, LyricsFoundEvent, LyricsLine, LyricsLineEvent, LyricsNotFoundEvent, ManagerEvents, ManagerInitOptions, ManagerOptions, MemoryStats, NodeLinkGetLyrics, NodeLinkGetLyricsEmpty, NodeLinkGetLyricsError, NodeLinkGetLyricsMultiple, NodeLinkGetLyricsSingle, NodeMessage, NodeOptions, NodeStats, PlayOptions, PlayerEvent, PlayerEventType, PlayerEvents, PlayerOptions, PlayerStateUpdateEvent, PlayerUpdateVoiceState, PlaylistData, PlaylistInfoData, PlaylistRawData, PlaylistSearchResult, PodcastSearchResult, PortableMessage, PortableUser, RedisConfig, RestPlayOptions, ReverbOptions, RotationOptions, SearchQuery, SearchResult, SearchSearchResult, Severity, ShortSearchResult, ShowSearchResult, Sizes, SponsorBlockChapterStarted, SponsorBlockChaptersLoaded, SponsorBlockSegmentEventType, SponsorBlockSegmentEvents, SponsorBlockSegmentSkipped, SponsorBlockSegmentsLoaded, StartSpeakingEventVoiceReceiver, StartSpeakingEventVoiceReceiverData, StateStorageOptions, StationSearchResult, TimescaleOptions, Track, TrackData, TrackDataInfo, TrackEndEvent, TrackEndReason, TrackExceptionEvent, TrackPluginInfo, TrackSearchResult, TrackSourceName, TrackStartEvent, TrackStuckEvent, UseNodeOption, VibratoOptions, VoicePacket, VoiceReceiverEvent, VoiceServer, VoiceServerUpdate, VoiceState, WebSocketClosedEvent };
@@ -31,11 +31,7 @@ class RedisQueue {
31
31
  this.guildId = guildId;
32
32
  this.manager = manager;
33
33
  this.redis = manager.redis;
34
- const rawPrefix = manager.options.stateStorage.redisConfig.prefix;
35
- let clean = typeof rawPrefix === "string" ? rawPrefix.trim() : "";
36
- if (!clean.endsWith(":"))
37
- clean = clean || "magmastream";
38
- this.redisPrefix = `${clean}:`;
34
+ this.redisPrefix = Utils_1.PlayerUtils.getRedisKey();
39
35
  }
40
36
  // #region Public
41
37
  /**
@@ -471,9 +471,7 @@ class Manager extends events_1.EventEmitter {
471
471
  case Enums_1.StateStorageType.Redis:
472
472
  {
473
473
  try {
474
- const redisKey = `${this.options.stateStorage.redisConfig.prefix?.endsWith(":")
475
- ? this.options.stateStorage.redisConfig.prefix
476
- : (this.options.stateStorage.redisConfig.prefix ?? "magmastream:")}playerstore:${guildId}`;
474
+ const redisKey = `${Utils_1.PlayerUtils.getRedisKey()}playerstore:${guildId}`;
477
475
  await this.redis.set(redisKey, JSON.stringify(serializedPlayer));
478
476
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved to Redis: ${guildId}`);
479
477
  }
@@ -726,9 +724,7 @@ class Manager extends events_1.EventEmitter {
726
724
  {
727
725
  try {
728
726
  // Get all keys matching our pattern
729
- const redisKeyPattern = `${this.options.stateStorage.redisConfig.prefix?.endsWith(":")
730
- ? this.options.stateStorage.redisConfig.prefix
731
- : (this.options.stateStorage.redisConfig.prefix ?? "magmastream:")}playerstore:*`;
727
+ const redisKeyPattern = `${Utils_1.PlayerUtils.getRedisKey()}playerstore:*`;
732
728
  const keys = await this.redis.keys(redisKeyPattern);
733
729
  for (const key of keys) {
734
730
  try {
@@ -1175,9 +1171,7 @@ class Manager extends events_1.EventEmitter {
1175
1171
  break;
1176
1172
  case Enums_1.StateStorageType.Redis:
1177
1173
  {
1178
- const prefix = this.options.stateStorage.redisConfig.prefix?.endsWith(":")
1179
- ? this.options.stateStorage.redisConfig.prefix
1180
- : (this.options.stateStorage.redisConfig.prefix ?? "magmastream:");
1174
+ const prefix = Utils_1.PlayerUtils.getRedisKey();
1181
1175
  const pattern = `${prefix}queue:*:current`;
1182
1176
  try {
1183
1177
  const stream = this.redis.scanStream({
@@ -1250,9 +1244,7 @@ class Manager extends events_1.EventEmitter {
1250
1244
  {
1251
1245
  try {
1252
1246
  if (!player) {
1253
- const prefix = this.options.stateStorage.redisConfig.prefix?.endsWith(":")
1254
- ? this.options.stateStorage.redisConfig.prefix
1255
- : `${this.options.stateStorage.redisConfig.prefix ?? "magmastream"}:`;
1247
+ const prefix = Utils_1.PlayerUtils.getRedisKey();
1256
1248
  const keysToDelete = [
1257
1249
  `${prefix}playerstore:${guildId}`,
1258
1250
  `${prefix}queue:${guildId}:tracks`,
@@ -1360,9 +1352,7 @@ class Manager extends events_1.EventEmitter {
1360
1352
  break;
1361
1353
  }
1362
1354
  case Enums_1.StateStorageType.Redis: {
1363
- const prefix = this.options.stateStorage.redisConfig.prefix?.endsWith(":")
1364
- ? this.options.stateStorage.redisConfig.prefix
1365
- : (this.options.stateStorage.redisConfig.prefix ?? "magmastream:");
1355
+ const prefix = Utils_1.PlayerUtils.getRedisKey();
1366
1356
  const patterns = [`${prefix}playerstore:*`, `${prefix}queue:*`];
1367
1357
  try {
1368
1358
  for (const pattern of patterns) {
@@ -125,6 +125,19 @@ class Node {
125
125
  get address() {
126
126
  return `${this.options.host}:${this.options.port}`;
127
127
  }
128
+ getCompositeKey() {
129
+ return `${this.options.identifier}::${this.manager.options.clusterId}`;
130
+ }
131
+ getRedisSessionIdsKey() {
132
+ return `${this.redisPrefix}node:sessionIds`;
133
+ }
134
+ getNodeSessionsDir() {
135
+ return path_1.default.join(process.cwd(), "magmastream", "sessionData", "cluster", String(this.manager.options.clusterId), "nodeSessions");
136
+ }
137
+ getNodeSessionPath() {
138
+ const safeId = String(this.options.identifier).replace(/[^a-zA-Z0-9._-]/g, "_");
139
+ return path_1.default.join(this.getNodeSessionsDir(), `${safeId}.txt`);
140
+ }
128
141
  /**
129
142
  * Creates the sessionIds.json file if it doesn't exist. This file is used to
130
143
  * store the session IDs for each node. The session IDs are used to identify
@@ -148,49 +161,43 @@ class Node {
148
161
  switch (this.manager.options.stateStorage.type) {
149
162
  case Enums_1.StateStorageType.Memory:
150
163
  case Enums_1.StateStorageType.JSON: {
151
- if (fs_1.default.existsSync(this.sessionIdsFilePath)) {
152
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Loading sessionIds from file: ${this.sessionIdsFilePath}`);
153
- const sessionIdsData = fs_1.default.readFileSync(this.sessionIdsFilePath, "utf-8");
154
- this.sessionIdsMap = new Map(Object.entries(JSON.parse(sessionIdsData)));
155
- const compositeKey = `${this.options.identifier}::${this.manager.options.clusterId}`;
156
- if (this.sessionIdsMap.has(compositeKey)) {
157
- this.sessionId = this.sessionIdsMap.get(compositeKey);
158
- }
164
+ const dir = this.getNodeSessionsDir();
165
+ const filePath = this.getNodeSessionPath();
166
+ if (!fs_1.default.existsSync(dir))
167
+ fs_1.default.mkdirSync(dir, { recursive: true });
168
+ if (!fs_1.default.existsSync(filePath)) {
169
+ this.sessionId = null;
170
+ return;
171
+ }
172
+ try {
173
+ const raw = fs_1.default.readFileSync(filePath, "utf-8").trim();
174
+ this.sessionId = raw.length ? raw : null;
175
+ if (this.sessionId)
176
+ this.sessionIdsMap.set(this.getCompositeKey(), this.sessionId);
177
+ }
178
+ catch {
179
+ this.sessionId = null;
159
180
  }
160
181
  break;
161
182
  }
162
- case Enums_1.StateStorageType.Redis:
163
- const key = `${this.redisPrefix}node:sessionIds`;
164
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Loading sessionIds from Redis key: ${key}`);
165
- const currentRaw = await this.manager.redis.get(key);
166
- if (currentRaw) {
167
- try {
168
- const sessionIds = JSON.parse(currentRaw);
169
- if (typeof sessionIds !== "object" || Array.isArray(sessionIds)) {
170
- throw new MagmastreamError_1.MagmaStreamError({
171
- code: Enums_1.MagmaStreamErrorCode.NODE_SESSION_IDS_LOAD_FAILED,
172
- message: "Invalid sessionIds data type from Redis.",
173
- context: { sessionIds },
174
- });
175
- }
176
- this.sessionIdsMap = new Map(Object.entries(sessionIds));
177
- const compositeKey = `${this.options.identifier}::${this.manager.options.clusterId}`;
178
- if (this.sessionIdsMap.has(compositeKey)) {
179
- this.sessionId = this.sessionIdsMap.get(compositeKey) || null;
180
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Restored sessionId for ${compositeKey}: ${this.sessionId}`);
181
- }
182
- }
183
- catch (err) {
184
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Failed to parse Redis sessionIds: ${err.message}`);
185
- this.sessionIdsMap = new Map();
183
+ case Enums_1.StateStorageType.Redis: {
184
+ const key = this.getRedisSessionIdsKey();
185
+ const compositeKey = this.getCompositeKey();
186
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Loading sessionId from Redis hash: ${key} field: ${compositeKey}`);
187
+ try {
188
+ const sid = await this.manager.redis.hget(key, compositeKey);
189
+ this.sessionId = sid ?? null;
190
+ if (this.sessionId) {
191
+ this.sessionIdsMap.set(compositeKey, this.sessionId);
192
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Restored sessionId for ${compositeKey}: ${this.sessionId}`);
186
193
  }
187
194
  }
188
- else {
189
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] No sessionIds found in Redis creating new key.`);
190
- await this.manager.redis.set(key, Utils_1.JSONUtils.safe({}));
191
- this.sessionIdsMap = new Map();
195
+ catch (err) {
196
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Failed to load sessionId from Redis hash: ${err.message}`);
197
+ this.sessionId = null;
192
198
  }
193
199
  break;
200
+ }
194
201
  }
195
202
  }
196
203
  /**
@@ -207,85 +214,54 @@ class Node {
207
214
  async updateSessionId() {
208
215
  switch (this.manager.options.stateStorage.type) {
209
216
  case Enums_1.StateStorageType.Memory:
210
- case Enums_1.StateStorageType.JSON: {
211
- const compositeKey = `${this.options.identifier}::${this.manager.options.clusterId}`;
212
- const filePath = this.sessionIdsFilePath;
213
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Updating sessionIds to file: ${filePath}`);
214
- let updated = false;
215
- let retries = 3;
216
- while (!updated && retries > 0) {
217
- try {
218
- let fileData = {};
219
- if (fs_1.default.existsSync(filePath)) {
220
- try {
221
- const raw = fs_1.default.readFileSync(filePath, "utf-8");
222
- fileData = raw.trim() ? JSON.parse(raw) : {};
223
- }
224
- catch (err) {
225
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Failed to read/parse sessionIds.json: ${err.message}`);
226
- fileData = {};
227
- }
228
- }
229
- fileData[compositeKey] = this.sessionId;
230
- const tmpPath = `${filePath}.tmp`;
231
- fs_1.default.writeFileSync(tmpPath, Utils_1.JSONUtils.safe(fileData, 2), "utf-8");
232
- fs_1.default.renameSync(tmpPath, filePath);
233
- this.sessionIdsMap = new Map(Object.entries(fileData));
234
- updated = true;
235
- }
236
- catch (err) {
237
- retries--;
238
- if (retries === 0) {
239
- throw new MagmastreamError_1.MagmaStreamError({
240
- code: Enums_1.MagmaStreamErrorCode.NODE_SESSION_IDS_UPDATE_FAILED,
241
- message: `Failed to update sessionIds after retries.`,
242
- cause: err instanceof Error ? err : undefined,
243
- context: { filePath, compositeKey, storage: "file" },
244
- });
245
- }
246
- await new Promise((r) => setTimeout(r, 50));
247
- }
248
- }
249
- break;
217
+ case Enums_1.StateStorageType.JSON:
218
+ return this.updateSessionIdFile();
219
+ case Enums_1.StateStorageType.Redis:
220
+ return this.updateSessionIdRedis();
221
+ }
222
+ }
223
+ async updateSessionIdFile() {
224
+ const dir = this.getNodeSessionsDir();
225
+ const filePath = this.getNodeSessionPath();
226
+ const tmpPath = `${filePath}.tmp`;
227
+ if (!fs_1.default.existsSync(dir))
228
+ fs_1.default.mkdirSync(dir, { recursive: true });
229
+ if (this.sessionId) {
230
+ fs_1.default.writeFileSync(tmpPath, this.sessionId, "utf-8");
231
+ fs_1.default.renameSync(tmpPath, filePath);
232
+ this.sessionIdsMap.set(this.getCompositeKey(), this.sessionId);
233
+ }
234
+ else {
235
+ try {
236
+ if (fs_1.default.existsSync(filePath))
237
+ fs_1.default.unlinkSync(filePath);
250
238
  }
251
- case Enums_1.StateStorageType.Redis: {
252
- const key = `${this.redisPrefix}node:sessionIds`;
253
- const compositeKey = `${this.options.identifier}::${this.manager.options.clusterId}`;
254
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Updating sessionIds in Redis key: ${key}`);
255
- let sessionIds = {};
256
- try {
257
- const currentRaw = await this.manager.redis.get(key);
258
- if (currentRaw) {
259
- sessionIds = JSON.parse(currentRaw);
260
- if (typeof sessionIds !== "object" || Array.isArray(sessionIds)) {
261
- throw new Error("Invalid data type in Redis");
262
- }
263
- }
264
- else {
265
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Redis key not found — creating new sessionIds key.`);
266
- sessionIds = {};
267
- }
268
- }
269
- catch (err) {
270
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Corrupted Redis sessionIds, reinitializing: ${err.message}`);
271
- sessionIds = {};
272
- }
273
- try {
274
- sessionIds[compositeKey] = this.sessionId;
275
- this.sessionIdsMap = new Map(Object.entries(sessionIds));
276
- await this.manager.redis.set(key, Utils_1.JSONUtils.safe(sessionIds));
277
- }
278
- catch (err) {
279
- throw new MagmastreamError_1.MagmaStreamError({
280
- code: Enums_1.MagmaStreamErrorCode.NODE_SESSION_IDS_UPDATE_FAILED,
281
- message: `Failed to update sessionIds in Redis.`,
282
- cause: err instanceof Error ? err : undefined,
283
- context: { key, compositeKey, storage: "redis" },
284
- });
285
- }
286
- break;
239
+ catch { }
240
+ this.sessionIdsMap.delete(this.getCompositeKey());
241
+ }
242
+ }
243
+ async updateSessionIdRedis() {
244
+ const key = this.getRedisSessionIdsKey();
245
+ const compositeKey = this.getCompositeKey();
246
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Updating sessionId in Redis hash: ${key} field: ${compositeKey}`);
247
+ try {
248
+ if (this.sessionId) {
249
+ await this.manager.redis.hset(key, compositeKey, this.sessionId);
250
+ this.sessionIdsMap.set(compositeKey, this.sessionId);
251
+ }
252
+ else {
253
+ await this.manager.redis.hdel(key, compositeKey);
254
+ this.sessionIdsMap.delete(compositeKey);
287
255
  }
288
256
  }
257
+ catch (err) {
258
+ throw new MagmastreamError_1.MagmaStreamError({
259
+ code: Enums_1.MagmaStreamErrorCode.NODE_SESSION_IDS_UPDATE_FAILED,
260
+ message: "Failed to update sessionId in Redis hash.",
261
+ cause: err instanceof Error ? err : undefined,
262
+ context: { key, compositeKey, storage: "redis-hash" },
263
+ });
264
+ }
289
265
  }
290
266
  /**
291
267
  * Connects to the Node.
@@ -305,12 +281,7 @@ class Node {
305
281
  "User-Id": this.manager.options.clientId,
306
282
  "Client-Name": this.manager.options.clientName,
307
283
  };
308
- const compositeKey = `${this.options.identifier}::${this.manager.options.clusterId}`;
309
- if (this.sessionId) {
310
- headers["Session-Id"] = this.sessionId;
311
- }
312
- else if (this.options.enableSessionResumeOption && this.sessionIdsMap.has(compositeKey)) {
313
- this.sessionId = this.sessionIdsMap.get(compositeKey) || null;
284
+ if (typeof this.sessionId === "string" && this.sessionId.length > 0) {
314
285
  headers["Session-Id"] = this.sessionId;
315
286
  }
316
287
  this.socket = new ws_1.default(`ws${this.options.useSSL ? "s" : ""}://${this.address}/v4/websocket`, { headers });
@@ -82,7 +82,7 @@ class Player {
82
82
  message: "Manager instance is required.",
83
83
  });
84
84
  }
85
- this.clusterId = this.manager.options.clusterId || 0;
85
+ this.clusterId = this.manager.options.clusterId ?? 0;
86
86
  // Check the player options for errors.
87
87
  (0, playerCheck_1.default)(options);
88
88
  this.options = {
@@ -737,7 +737,7 @@ class PlayerUtils {
737
737
  * Gets the base directory for player data.
738
738
  */
739
739
  static getPlayersBaseDir() {
740
- return path_1.default.join(process.cwd(), "magmastream", "sessionData", "players");
740
+ return path_1.default.join(process.cwd(), "magmastream", "sessionData", "cluster", String(this.manager.options.clusterId), "players");
741
741
  }
742
742
  /**
743
743
  * Gets the path to the player's directory.
@@ -769,6 +769,17 @@ class PlayerUtils {
769
769
  static getPlayerPreviousPath(guildId) {
770
770
  return path_1.default.join(this.getGuildDir(guildId), "previous.json");
771
771
  }
772
+ /**
773
+ * Gets the Redis key for player storage.
774
+ */
775
+ static getRedisKey() {
776
+ const cfg = this.manager.options.stateStorage.redisConfig;
777
+ // Default prefix
778
+ let prefix = (cfg.prefix ?? "magmastream:").trim();
779
+ prefix = prefix.replace(/:+$/g, "") + ":";
780
+ const clusterId = String(this.manager.options.clusterId ?? 0).trim() || "0";
781
+ return `${prefix}cluster:${clusterId}:`;
782
+ }
772
783
  }
773
784
  exports.PlayerUtils = PlayerUtils;
774
785
  /** Gets or extends structures to extend the built in, or already extended, classes to add more functionality. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magmastream",
3
- "version": "2.9.3-dev.17",
3
+ "version": "2.9.3-dev.19",
4
4
  "description": "A user-friendly Lavalink client designed for NodeJS.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",