magmastream 2.9.1-dev.2 → 2.9.1-dev.4

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
@@ -1,13 +1,13 @@
1
1
  import { Collection } from '@discordjs/collection';
2
2
  import { GatewayVoiceStateUpdate } from 'discord-api-types/v10';
3
3
  import { EventEmitter } from 'events';
4
- import { User, ClientUser, Message, Client } from 'discord.js';
4
+ import { Message, User, ClientUser, Client } from 'discord.js';
5
5
  import WebSocket$1, { WebSocket } from 'ws';
6
6
  import { Redis } from 'ioredis';
7
- import { Client as Client$1 } from 'eris';
7
+ import { Client as Client$1, User as User$1 } from 'eris';
8
8
  import { ClusterClient, ShardClient } from 'detritus-client';
9
- import { Client as Client$2 } from 'oceanic.js';
10
- import { Client as Client$3, WorkerClient } from 'seyfert';
9
+ import { Client as Client$2, User as User$2 } from 'oceanic.js';
10
+ import { Client as Client$3, WorkerClient, User as User$3 } from 'seyfert';
11
11
 
12
12
  /** Represents an equalizer band. */
13
13
  interface Band {
@@ -897,6 +897,13 @@ interface NodeOptions {
897
897
  */
898
898
  isBackup?: boolean;
899
899
  }
900
+ /**
901
+ * Portable User
902
+ */
903
+ interface PortableUser {
904
+ id: string;
905
+ username?: string;
906
+ }
900
907
  /**
901
908
  * Discord Packet
902
909
  */
@@ -1102,7 +1109,7 @@ interface Track {
1102
1109
  /** The thumbnail of the track or null if it's a unsupported source. */
1103
1110
  readonly thumbnail: string | null;
1104
1111
  /** The user that requested the track. */
1105
- requester?: User | ClientUser;
1112
+ requester?: PortableUser;
1106
1113
  /** Displays the track thumbnail with optional size or null if it's a unsupported source. */
1107
1114
  displayThumbnail(size?: Sizes): string;
1108
1115
  /** Additional track info provided by plugins. */
@@ -1287,7 +1294,7 @@ interface PlaylistData {
1287
1294
  /** The playlist name. */
1288
1295
  name: string;
1289
1296
  /** Requester of playlist. */
1290
- requester: User | ClientUser;
1297
+ requester: PortableUser;
1291
1298
  /** More playlist information. */
1292
1299
  playlistInfo: PlaylistInfoData[];
1293
1300
  /** The length of the playlist. */
@@ -2103,12 +2110,12 @@ declare class Player {
2103
2110
  * track when the current track ends.
2104
2111
  *
2105
2112
  * @param {boolean} autoplayState - Whether or not autoplay should be enabled.
2106
- * @param {object} botUser - The user-object that should be used as the bot-user.
2113
+ * @param {object} AutoplayUser - The user-object that should be used as the bot-user.
2107
2114
  * @param {number} [tries=3] - The number of times the player should try to find a
2108
2115
  * recommended track if the first one doesn't work.
2109
2116
  * @returns {this} - The player instance.
2110
2117
  */
2111
- setAutoplay<T = unknown>(autoplayState: boolean, botUser?: T, tries?: number): this;
2118
+ setAutoplay<T = unknown>(autoplayState: boolean, AutoplayUser?: T, tries?: number): this;
2112
2119
  /**
2113
2120
  * Gets recommended tracks and returns an array of tracks.
2114
2121
  * @param {Track} track - The track to find recommendations for.
@@ -2998,6 +3005,11 @@ declare class Manager extends EventEmitter {
2998
3005
  private get priorityNode();
2999
3006
  protected send(packet: GatewayVoiceStateUpdate): unknown;
3000
3007
  sendPacket(packet: GatewayVoiceStateUpdate): unknown;
3008
+ /**
3009
+ * Resolves a PortableUser or ID to a real user object.
3010
+ * Can be overridden by wrapper managers to return wrapper-specific User classes.
3011
+ */
3012
+ resolveUser(user: PortableUser | string): Promise<PortableUser>;
3001
3013
  }
3002
3014
 
3003
3015
  declare class Filters {
@@ -3376,7 +3388,7 @@ declare abstract class TrackUtils {
3376
3388
  * @param requester The user who requested the track, if any.
3377
3389
  * @returns The built Track.
3378
3390
  */
3379
- static build<T = User | ClientUser>(data: TrackData, requester?: T): Track;
3391
+ static build<T = PortableUser | User | ClientUser>(data: TrackData, requester?: T): Track;
3380
3392
  /**
3381
3393
  * Validates a search result.
3382
3394
  * @param result The search result to validate.
@@ -3487,6 +3499,9 @@ declare abstract class Structure {
3487
3499
  */
3488
3500
  static get<K extends keyof Extendable>(name: K): Extendable[K];
3489
3501
  }
3502
+ declare abstract class JSONUtils {
3503
+ static safe<T>(obj: T, space?: number): string;
3504
+ }
3490
3505
 
3491
3506
  /**
3492
3507
  * Discord.js wrapper for Magmastream.
@@ -3495,6 +3510,7 @@ declare class DiscordJSManager extends Manager {
3495
3510
  readonly client: Client;
3496
3511
  constructor(client: Client, options?: ManagerOptions);
3497
3512
  protected send(packet: GatewayVoiceStateUpdate): void;
3513
+ resolveUser(user: PortableUser | string): Promise<User | PortableUser>;
3498
3514
  }
3499
3515
 
3500
3516
  /**
@@ -3504,6 +3520,7 @@ declare class ErisManager extends Manager {
3504
3520
  readonly client: Client$1;
3505
3521
  constructor(client: Client$1, options?: ManagerOptions);
3506
3522
  protected send(packet: GatewayVoiceStateUpdate): void;
3523
+ resolveUser(user: PortableUser | string): Promise<User$1 | PortableUser>;
3507
3524
  }
3508
3525
 
3509
3526
  /**
@@ -3513,6 +3530,7 @@ declare class DetritusManager extends Manager {
3513
3530
  readonly client: ClusterClient | ShardClient;
3514
3531
  constructor(client: ClusterClient | ShardClient, options?: ManagerOptions);
3515
3532
  protected send(packet: GatewayVoiceStateUpdate): void;
3533
+ resolveUser(user: PortableUser | string): Promise<PortableUser>;
3516
3534
  }
3517
3535
 
3518
3536
  /**
@@ -3522,6 +3540,7 @@ declare class OceanicManager extends Manager {
3522
3540
  readonly client: Client$2;
3523
3541
  constructor(client: Client$2, options?: ManagerOptions);
3524
3542
  protected send(packet: GatewayVoiceStateUpdate): void;
3543
+ resolveUser(user: PortableUser | string): Promise<User$2 | PortableUser>;
3525
3544
  }
3526
3545
 
3527
3546
  /**
@@ -3553,7 +3572,8 @@ declare class SeyfertManager extends Manager {
3553
3572
  readonly client: Client$3 | WorkerClient;
3554
3573
  constructor(client: Client$3 | WorkerClient, options?: ManagerOptions);
3555
3574
  protected send(packet: GatewayVoiceStateUpdate): void;
3575
+ resolveUser(user: PortableUser | string): Promise<User$3 | PortableUser>;
3556
3576
  }
3557
3577
 
3558
- export { AutoPlayPlatform, AutoPlayUtils, AvailableFilters, DetritusManager, DiscordJSManager, ErisManager, Filters, JsonQueue, LoadTypes, Manager, ManagerEventTypes, MemoryQueue, Node, OceanicManager, Player, PlayerStateEventTypes, PlayerUtils, Plugin, RedisQueue, Rest, SearchPlatform, SeverityTypes, SeyfertManager, SponsorBlockSegment, StateStorageType, StateTypes, Structure, TrackEndReasonTypes, TrackPartial, TrackSourceTypes, TrackUtils, UseNodeOptions };
3559
- export type { AlbumSearchResult, 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, 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 };
3578
+ export { AutoPlayPlatform, AutoPlayUtils, AvailableFilters, DetritusManager, DiscordJSManager, ErisManager, Filters, JSONUtils, JsonQueue, LoadTypes, Manager, ManagerEventTypes, MemoryQueue, Node, OceanicManager, Player, PlayerStateEventTypes, PlayerUtils, Plugin, RedisQueue, Rest, SearchPlatform, SeverityTypes, SeyfertManager, SponsorBlockSegment, StateStorageType, StateTypes, Structure, TrackEndReasonTypes, TrackPartial, TrackSourceTypes, TrackUtils, UseNodeOptions };
3579
+ export type { AlbumSearchResult, 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, 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 };
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const Enums_1 = require("../structures/Enums");
6
6
  const path_1 = tslib_1.__importDefault(require("path"));
7
7
  const fs_1 = require("fs");
8
+ const Utils_1 = require("../structures/Utils");
8
9
  /**
9
10
  * The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
10
11
  */
@@ -53,8 +54,8 @@ class JsonQueue {
53
54
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[JSONQUEUE] Added ${tracks.length} track(s) to queue`);
54
55
  if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
55
56
  if (!isArray) {
56
- const botUser = (await this.manager.players.get(this.guildId).get("Internal_BotUser"));
57
- if (botUser && botUser.id === track.requester.id) {
57
+ const AutoplayUser = (await this.manager.players.get(this.guildId).get("Internal_AutoplayUser"));
58
+ if (AutoplayUser && AutoplayUser.id === track.requester.id) {
58
59
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
59
60
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
60
61
  details: {
@@ -437,7 +438,7 @@ class JsonQueue {
437
438
  */
438
439
  async writeJSON(filePath, data) {
439
440
  await this.ensureDir();
440
- await fs_1.promises.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
441
+ await fs_1.promises.writeFile(filePath, Utils_1.JSONUtils.safe(data, 2), "utf-8");
441
442
  }
442
443
  }
443
444
  exports.JsonQueue = JsonQueue;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MemoryQueue = void 0;
4
4
  const Enums_1 = require("../structures/Enums");
5
+ const Utils_1 = require("../structures/Utils");
5
6
  /**
6
7
  * The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
7
8
  */
@@ -36,7 +37,7 @@ class MemoryQueue extends Array {
36
37
  const isArray = Array.isArray(track);
37
38
  const tracks = isArray ? [...track] : [track];
38
39
  // Get the track info as a string
39
- const trackInfo = isArray ? tracks.map((t) => JSON.stringify(t, null, 2)).join(", ") : JSON.stringify(track, null, 2);
40
+ const trackInfo = isArray ? tracks.map((t) => Utils_1.JSONUtils.safe(t, 2)).join(", ") : Utils_1.JSONUtils.safe(track, 2);
40
41
  // Emit a debug message
41
42
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Added ${tracks.length} track(s) to queue: ${trackInfo}`);
42
43
  const oldPlayer = this.manager.players.get(this.guildId) ? { ...this.manager.players.get(this.guildId) } : null;
@@ -81,8 +82,8 @@ class MemoryQueue extends Array {
81
82
  }
82
83
  if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
83
84
  if (!isArray) {
84
- const botUser = this.manager.players.get(this.guildId).get("Internal_BotUser");
85
- if (botUser && botUser.id === track.requester.id) {
85
+ const AutoplayUser = this.manager.players.get(this.guildId).get("Internal_AutoplayUser");
86
+ if (AutoplayUser && AutoplayUser.id === track.requester.id) {
86
87
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
87
88
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
88
89
  details: {
@@ -262,7 +263,7 @@ class MemoryQueue extends Array {
262
263
  }
263
264
  // Single item removal when no end specified
264
265
  const removedTrack = this.splice(startOrPosition, 1);
265
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Removed 1 track from player: ${this.guildId} from position ${startOrPosition}: ${JSON.stringify(removedTrack[0], null, 2)}`);
266
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Removed 1 track from player: ${this.guildId} from position ${startOrPosition}: ${Utils_1.JSONUtils.safe(removedTrack[0], 2)}`);
266
267
  // Ensure removedTrack is an array for consistency
267
268
  const tracksToEmit = removedTrack.length > 0 ? removedTrack : [];
268
269
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RedisQueue = void 0;
4
4
  const Enums_1 = require("../structures/Enums");
5
+ const Utils_1 = require("../structures/Utils");
5
6
  /**
6
7
  * The player's queue, the `current` property is the currently playing track, think of the rest as the up-coming tracks.
7
8
  */
@@ -61,8 +62,8 @@ class RedisQueue {
61
62
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Added ${tracks.length} track(s) to queue`);
62
63
  if (this.manager.players.has(this.guildId) && this.manager.players.get(this.guildId).isAutoplay) {
63
64
  if (!Array.isArray(track)) {
64
- const botUser = (await this.manager.players.get(this.guildId).get("Internal_BotUser"));
65
- if (botUser && botUser.id === track.requester.id) {
65
+ const AutoplayUser = (await this.manager.players.get(this.guildId).get("Internal_AutoplayUser"));
66
+ if (AutoplayUser && AutoplayUser.id === track.requester.id) {
66
67
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
67
68
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
68
69
  details: {
@@ -441,7 +442,7 @@ class RedisQueue {
441
442
  * Helper to serialize/deserialize Track
442
443
  */
443
444
  serialize(track) {
444
- return JSON.stringify(track);
445
+ return Utils_1.JSONUtils.safe(track, 2);
445
446
  }
446
447
  }
447
448
  exports.RedisQueue = RedisQueue;
@@ -180,22 +180,26 @@ class Manager extends events_1.EventEmitter {
180
180
  throw new Error("No available nodes.");
181
181
  const _query = typeof query === "string" ? { query } : query;
182
182
  const _source = _query.source ?? this.options.defaultSearchPlatform;
183
- let search = /^https?:\/\//.test(_query.query) ? _query.query : `${_source}:${_query.query}`;
184
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Performing ${_source} search for: ${_query.query}`);
183
+ const isUrl = /^https?:\/\//.test(_query.query);
184
+ const search = isUrl ? _query.query : `${_source}:${_query.query}`;
185
+ this.emit(Enums_1.ManagerEventTypes.Debug, isUrl ? `[MANAGER] Performing search for: ${_query.query}` : `[MANAGER] Performing ${_source} search for: ${_query.query}`);
185
186
  try {
186
187
  const res = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(search)}`));
187
188
  if (!res)
188
189
  throw new Error("Query not found.");
189
- let tracks = [];
190
- let playlist = null;
190
+ let result;
191
191
  switch (res.loadType) {
192
- case Enums_1.LoadTypes.Search:
193
- tracks = res.data.map((track) => Utils_1.TrackUtils.build(track, requester));
192
+ case Enums_1.LoadTypes.Search: {
193
+ const tracks = res.data.map((t) => Utils_1.TrackUtils.build(t, requester));
194
+ result = { loadType: res.loadType, tracks };
194
195
  break;
196
+ }
195
197
  case Enums_1.LoadTypes.Short:
196
- case Enums_1.LoadTypes.Track:
197
- tracks = [Utils_1.TrackUtils.build(res.data, requester)];
198
+ case Enums_1.LoadTypes.Track: {
199
+ const track = Utils_1.TrackUtils.build(res.data, requester);
200
+ result = { loadType: res.loadType, tracks: [track] };
198
201
  break;
202
+ }
199
203
  case Enums_1.LoadTypes.Album:
200
204
  case Enums_1.LoadTypes.Artist:
201
205
  case Enums_1.LoadTypes.Station:
@@ -203,18 +207,24 @@ class Manager extends events_1.EventEmitter {
203
207
  case Enums_1.LoadTypes.Show:
204
208
  case Enums_1.LoadTypes.Playlist: {
205
209
  const playlistData = res.data;
206
- tracks = playlistData.tracks.map((track) => Utils_1.TrackUtils.build(track, requester));
207
- playlist = {
208
- name: playlistData.info.name,
209
- playlistInfo: playlistData.pluginInfo,
210
- requester: requester,
210
+ const tracks = playlistData.tracks.map((t) => Utils_1.TrackUtils.build(t, requester));
211
+ result = {
212
+ loadType: res.loadType,
211
213
  tracks,
212
- duration: tracks.reduce((acc, cur) => acc + (cur.duration || 0), 0),
214
+ playlist: {
215
+ name: playlistData.info.name,
216
+ playlistInfo: playlistData.pluginInfo,
217
+ requester: requester,
218
+ tracks,
219
+ duration: tracks.reduce((acc, cur) => acc + (cur.duration || 0), 0),
220
+ },
213
221
  };
214
222
  break;
215
223
  }
224
+ default:
225
+ result = { loadType: res.loadType };
216
226
  }
217
- if (this.options.normalizeYouTubeTitles) {
227
+ if (this.options.normalizeYouTubeTitles && "tracks" in result) {
218
228
  const processTrack = (track) => {
219
229
  if (!/(youtube\.com|youtu\.be)/.test(track.uri))
220
230
  return track;
@@ -223,34 +233,15 @@ class Manager extends events_1.EventEmitter {
223
233
  track.author = cleanAuthor;
224
234
  return track;
225
235
  };
226
- if (playlist) {
227
- playlist.tracks = playlist.tracks.map(processTrack);
228
- }
229
- else {
230
- tracks = tracks.map(processTrack);
236
+ result.tracks = result.tracks.map(processTrack);
237
+ if ("playlist" in result && result.playlist) {
238
+ result.playlist.tracks = result.playlist.tracks.map(processTrack);
231
239
  }
232
240
  }
233
- let result;
234
- switch (res.loadType) {
235
- case Enums_1.LoadTypes.Album:
236
- case Enums_1.LoadTypes.Artist:
237
- case Enums_1.LoadTypes.Station:
238
- case Enums_1.LoadTypes.Podcast:
239
- case Enums_1.LoadTypes.Show:
240
- case Enums_1.LoadTypes.Playlist:
241
- result = { loadType: res.loadType, tracks, playlist };
242
- break;
243
- case Enums_1.LoadTypes.Search:
244
- result = { loadType: res.loadType, tracks };
245
- break;
246
- case Enums_1.LoadTypes.Short:
247
- case Enums_1.LoadTypes.Track:
248
- result = { loadType: res.loadType, tracks: [tracks[0]] };
249
- break;
250
- default:
251
- return { loadType: res.loadType };
252
- }
253
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Result ${_source} search for: ${_query.query}: ${JSON.stringify(result)}`);
241
+ const summary = "tracks" in result
242
+ ? result.tracks.map((t) => Object.fromEntries(Object.entries(t).filter(([key]) => key !== "requester")))
243
+ : [];
244
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Result search for ${_query.query}: ${Utils_1.JSONUtils.safe(summary, 2)}`);
254
245
  return result;
255
246
  }
256
247
  catch (err) {
@@ -275,7 +266,7 @@ class Manager extends events_1.EventEmitter {
275
266
  return this.players.get(options.guildId);
276
267
  }
277
268
  // Create a new player with the given options
278
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Creating new player with options: ${JSON.stringify(options)}`);
269
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Creating new player with options: ${Utils_1.JSONUtils.safe(options, 2)}`);
279
270
  return new (Utils_1.Structure.get("Player"))(options);
280
271
  }
281
272
  /**
@@ -306,7 +297,7 @@ class Manager extends events_1.EventEmitter {
306
297
  // Set the node in the manager's collection
307
298
  this.nodes.set(key, node);
308
299
  // Emit a debug event for node creation
309
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Creating new node with options: ${JSON.stringify(options)}`);
300
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Creating new node with options: ${Utils_1.JSONUtils.safe(options, 2)}`);
310
301
  // Return the created node
311
302
  return node;
312
303
  }
@@ -350,7 +341,7 @@ class Manager extends events_1.EventEmitter {
350
341
  const player = this.getPlayer(update.guild_id);
351
342
  if (!player)
352
343
  return;
353
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Updating voice state: ${JSON.stringify(update)}`);
344
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Updating voice state: ${Utils_1.JSONUtils.safe(update, 2)}`);
354
345
  if ("token" in update) {
355
346
  return await this.handleVoiceServerUpdate(player, update);
356
347
  }
@@ -366,12 +357,12 @@ class Manager extends events_1.EventEmitter {
366
357
  * @throws Will throw an error if no nodes are available or if the API request fails.
367
358
  */
368
359
  async decodeTracks(tracks) {
369
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Decoding tracks: ${JSON.stringify(tracks)}`);
360
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Decoding tracks: ${Utils_1.JSONUtils.safe(tracks, 2)}`);
370
361
  return new Promise(async (resolve, reject) => {
371
362
  const node = this.nodes.first();
372
363
  if (!node)
373
364
  throw new Error("No available nodes.");
374
- const res = (await node.rest.post("/v4/decodetracks", JSON.stringify(tracks)).catch((err) => reject(err)));
365
+ const res = (await node.rest.post("/v4/decodetracks", Utils_1.JSONUtils.safe(tracks, 2)).catch((err) => reject(err)));
375
366
  if (!res) {
376
367
  return reject(new Error("No data returned from query."));
377
368
  }
@@ -407,7 +398,7 @@ class Manager extends events_1.EventEmitter {
407
398
  }
408
399
  const serializedPlayer = await Utils_1.PlayerUtils.serializePlayer(player);
409
400
  await promises_1.default.mkdir(path_1.default.dirname(playerStateFilePath), { recursive: true });
410
- await promises_1.default.writeFile(playerStateFilePath, JSON.stringify(serializedPlayer, null, 2), "utf-8");
401
+ await promises_1.default.writeFile(playerStateFilePath, Utils_1.JSONUtils.safe(serializedPlayer, 2), "utf-8");
411
402
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved: ${guildId}`);
412
403
  }
413
404
  catch (error) {
@@ -427,7 +418,7 @@ class Manager extends events_1.EventEmitter {
427
418
  const redisKey = `${this.options.stateStorage.redisConfig.prefix?.endsWith(":")
428
419
  ? this.options.stateStorage.redisConfig.prefix
429
420
  : this.options.stateStorage.redisConfig.prefix ?? "magmastream:"}playerstore:${guildId}`;
430
- await this.redis.set(redisKey, JSON.stringify(serializedPlayer));
421
+ await this.redis.set(redisKey, Utils_1.JSONUtils.safe(serializedPlayer, 2));
431
422
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved to Redis: ${guildId}`);
432
423
  }
433
424
  catch (error) {
@@ -497,7 +488,7 @@ class Manager extends events_1.EventEmitter {
497
488
  volume: lavaPlayer.volume || state.options.volume,
498
489
  nodeIdentifier: nodeId,
499
490
  };
500
- this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Recreating player: ${state.guildId} from saved file: ${JSON.stringify(state.options)}`);
491
+ this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Recreating player: ${state.guildId} from saved file: ${Utils_1.JSONUtils.safe(state.options, 2)}`);
501
492
  const player = this.create(playerOptions);
502
493
  await player.node.rest.updatePlayer({
503
494
  guildId: state.options.guildId,
@@ -514,8 +505,11 @@ class Manager extends events_1.EventEmitter {
514
505
  const currentTrack = state.queue.current;
515
506
  const queueTracks = state.queue.tracks;
516
507
  if (state.isAutoplay) {
517
- Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
518
- player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
508
+ const savedUser = state.data.clientUser;
509
+ if (savedUser) {
510
+ const autoPlayUser = await player.manager.resolveUser(savedUser);
511
+ player.setAutoplay(true, autoPlayUser, state.autoplayTries);
512
+ }
519
513
  }
520
514
  if (lavaPlayer?.track) {
521
515
  tracks.push(...queueTracks);
@@ -705,8 +699,11 @@ class Manager extends events_1.EventEmitter {
705
699
  const currentTrack = state.queue.current;
706
700
  const queueTracks = state.queue.tracks;
707
701
  if (state.isAutoplay) {
708
- Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
709
- player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
702
+ const savedUser = state.data.clientUser;
703
+ if (savedUser) {
704
+ const autoPlayUser = await player.manager.resolveUser(savedUser);
705
+ player.setAutoplay(true, autoPlayUser, state.autoplayTries);
706
+ }
710
707
  }
711
708
  if (lavaPlayer?.track) {
712
709
  // If lavaPlayer has a track, push all queue tracks
@@ -1310,5 +1307,16 @@ class Manager extends events_1.EventEmitter {
1310
1307
  sendPacket(packet) {
1311
1308
  return this.send(packet);
1312
1309
  }
1310
+ /**
1311
+ * Resolves a PortableUser or ID to a real user object.
1312
+ * Can be overridden by wrapper managers to return wrapper-specific User classes.
1313
+ */
1314
+ async resolveUser(user) {
1315
+ if (!user)
1316
+ return null;
1317
+ if (typeof user === "string")
1318
+ return { id: user }; // fallback by ID only
1319
+ return user; // default: just return the portable user
1320
+ }
1313
1321
  }
1314
1322
  exports.Manager = Manager;
@@ -128,7 +128,7 @@ class Node {
128
128
  createSessionIdsFile() {
129
129
  if (!fs_1.default.existsSync(this.sessionIdsFilePath)) {
130
130
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Creating sessionId file at: ${this.sessionIdsFilePath}`);
131
- fs_1.default.writeFileSync(this.sessionIdsFilePath, JSON.stringify({}), "utf-8");
131
+ fs_1.default.writeFileSync(this.sessionIdsFilePath, Utils_1.JSONUtils.safe({}), "utf-8");
132
132
  }
133
133
  }
134
134
  /**
@@ -178,7 +178,7 @@ class Node {
178
178
  }
179
179
  else {
180
180
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] No sessionIds found in Redis — creating new key.`);
181
- await this.manager.redis.set(key, JSON.stringify({}));
181
+ await this.manager.redis.set(key, Utils_1.JSONUtils.safe({}));
182
182
  this.sessionIdsMap = new Map();
183
183
  }
184
184
  break;
@@ -219,7 +219,7 @@ class Node {
219
219
  }
220
220
  fileData[compositeKey] = this.sessionId;
221
221
  const tmpPath = `${filePath}.tmp`;
222
- fs_1.default.writeFileSync(tmpPath, JSON.stringify(fileData, null, 2), "utf-8");
222
+ fs_1.default.writeFileSync(tmpPath, Utils_1.JSONUtils.safe(fileData, 2), "utf-8");
223
223
  fs_1.default.renameSync(tmpPath, filePath);
224
224
  this.sessionIdsMap = new Map(Object.entries(fileData));
225
225
  updated = true;
@@ -259,7 +259,7 @@ class Node {
259
259
  }
260
260
  sessionIds[compositeKey] = this.sessionId;
261
261
  this.sessionIdsMap = new Map(Object.entries(sessionIds));
262
- await this.manager.redis.set(key, JSON.stringify(sessionIds));
262
+ await this.manager.redis.set(key, Utils_1.JSONUtils.safe(sessionIds));
263
263
  break;
264
264
  }
265
265
  }
@@ -307,7 +307,7 @@ class Node {
307
307
  identifier: this.options.identifier,
308
308
  },
309
309
  };
310
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Connecting ${JSON.stringify(debugInfo)}`);
310
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Connecting ${Utils_1.JSONUtils.safe(debugInfo, 2)}`);
311
311
  }
312
312
  /**
313
313
  * Destroys the node and cleans up associated resources.
@@ -329,7 +329,7 @@ class Node {
329
329
  sessionId: this.sessionId,
330
330
  playerCount: this.manager.players.filter((p) => p.node == this).size,
331
331
  };
332
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Destroying node: ${JSON.stringify(debugInfo)}`);
332
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Destroying node: ${Utils_1.JSONUtils.safe(debugInfo, 2)}`);
333
333
  // Automove all players connected to that node
334
334
  const players = this.manager.players.filter((p) => p.node == this);
335
335
  if (players.size) {
@@ -368,7 +368,7 @@ class Node {
368
368
  maxRetryAttempts: this.options.maxRetryAttempts,
369
369
  retryDelayMs: this.options.retryDelayMs,
370
370
  };
371
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Reconnecting node: ${JSON.stringify(debugInfo)}`);
371
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Reconnecting node: ${Utils_1.JSONUtils.safe(debugInfo, 2)}`);
372
372
  this.reconnectTimeout = setTimeout(async () => {
373
373
  if (this.reconnectAttempts >= this.options.maxRetryAttempts) {
374
374
  const error = new Error(`Unable to connect after ${this.options.maxRetryAttempts} attempts.`);
@@ -405,7 +405,7 @@ class Node {
405
405
  identifier: this.options.identifier,
406
406
  connected: this.connected,
407
407
  };
408
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Connected node: ${JSON.stringify(debugInfo)}`);
408
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Connected node: ${Utils_1.JSONUtils.safe(debugInfo, 2)}`);
409
409
  this.manager.emit(Enums_1.ManagerEventTypes.NodeConnect, this);
410
410
  const playersOnBackupNode = this.manager.players.filter((p) => p.node.options.isBackup);
411
411
  if (playersOnBackupNode.size) {
@@ -432,7 +432,7 @@ class Node {
432
432
  reason,
433
433
  };
434
434
  this.manager.emit(Enums_1.ManagerEventTypes.NodeDisconnect, this, { code, reason });
435
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Disconnected node: ${JSON.stringify(debugInfo)}`);
435
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Disconnected node: ${Utils_1.JSONUtils.safe(debugInfo, 2)}`);
436
436
  if (this.manager.useableNode) {
437
437
  const players = this.manager.players.filter((p) => p.node.options.identifier == this.options.identifier);
438
438
  if (players.size) {
@@ -464,7 +464,7 @@ class Node {
464
464
  identifier: this.options.identifier,
465
465
  error: error.message,
466
466
  };
467
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Error on node: ${JSON.stringify(debugInfo)}`);
467
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Error on node: ${Utils_1.JSONUtils.safe(debugInfo, 2)}`);
468
468
  this.manager.emit(Enums_1.ManagerEventTypes.NodeError, this, error);
469
469
  }
470
470
  /**
@@ -504,11 +504,11 @@ class Node {
504
504
  if (player && player.node.options.identifier !== this.options.identifier) {
505
505
  return;
506
506
  }
507
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Node message: ${JSON.stringify(payload)}`);
507
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Node message: ${Utils_1.JSONUtils.safe(payload, 2)}`);
508
508
  await this.handleEvent(payload);
509
509
  break;
510
510
  case "ready":
511
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Node message: ${JSON.stringify(payload)}`);
511
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Node message: ${Utils_1.JSONUtils.safe(payload, 2)}`);
512
512
  this.rest.setSessionId(payload.sessionId);
513
513
  this.sessionId = payload.sessionId;
514
514
  await this.updateSessionId();
@@ -601,8 +601,8 @@ class Node {
601
601
  player.playing = true;
602
602
  player.paused = false;
603
603
  this.manager.emit(Enums_1.ManagerEventTypes.TrackStart, player, track, payload);
604
- const botUser = player.get("Internal_BotUser");
605
- if (botUser && botUser.id === track.requester.id) {
604
+ const AutoplayUser = player.get("Internal_AutoplayUser");
605
+ if (AutoplayUser && AutoplayUser.id === track.requester.id) {
606
606
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, player, {
607
607
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
608
608
  details: {
@@ -702,7 +702,7 @@ class Node {
702
702
  return false;
703
703
  const PreviousQueue = await player.queue.getPrevious();
704
704
  const lastTrack = PreviousQueue?.at(-1);
705
- lastTrack.requester = player.get("Internal_BotUser");
705
+ lastTrack.requester = player.get("Internal_AutoplayUser");
706
706
  if (!lastTrack)
707
707
  return false;
708
708
  const tracks = await Utils_1.AutoPlayUtils.getRecommendedTracks(lastTrack);
@@ -934,7 +934,7 @@ class Node {
934
934
  */
935
935
  socketClosed(player, payload) {
936
936
  this.manager.emit(Enums_1.ManagerEventTypes.SocketClosed, player, payload);
937
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Websocket closed for player: ${player.guildId} with payload: ${JSON.stringify(payload)}`);
937
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[NODE] Websocket closed for player: ${player.guildId} with payload: ${Utils_1.JSONUtils.safe(payload, 2)}`);
938
938
  }
939
939
  /**
940
940
  * Emitted when the segments for a track are loaded.
@@ -1045,7 +1045,7 @@ class Node {
1045
1045
  throw new RangeError("No Segments provided. Did you mean to use 'deleteSponsorBlock'?");
1046
1046
  if (segments.some((v) => !validSponsorBlocks.includes(v.toLowerCase())))
1047
1047
  throw new SyntaxError(`You provided a sponsorblock which isn't valid, valid ones are: ${validSponsorBlocks.map((v) => `'${v}'`).join(", ")}`);
1048
- await this.rest.put(`/v4/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, JSON.stringify(segments.map((v) => v.toLowerCase())));
1048
+ await this.rest.put(`/v4/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, Utils_1.JSONUtils.safe(segments.map((v) => v.toLowerCase()), 2));
1049
1049
  return;
1050
1050
  }
1051
1051
  /**
@@ -355,30 +355,27 @@ class Player {
355
355
  * track when the current track ends.
356
356
  *
357
357
  * @param {boolean} autoplayState - Whether or not autoplay should be enabled.
358
- * @param {object} botUser - The user-object that should be used as the bot-user.
358
+ * @param {object} AutoplayUser - The user-object that should be used as the bot-user.
359
359
  * @param {number} [tries=3] - The number of times the player should try to find a
360
360
  * recommended track if the first one doesn't work.
361
361
  * @returns {this} - The player instance.
362
362
  */
363
- setAutoplay(autoplayState, botUser, tries) {
363
+ setAutoplay(autoplayState, AutoplayUser, tries) {
364
364
  if (typeof autoplayState !== "boolean") {
365
365
  throw new Error("autoplayState must be a boolean.");
366
366
  }
367
367
  if (autoplayState) {
368
- if (!botUser) {
369
- throw new Error("botUser must be provided when enabling autoplay.");
370
- }
371
- if (!["ClientUser", "User"].includes(botUser.constructor.name)) {
372
- throw new Error("botUser must be a user-object.");
368
+ if (!AutoplayUser) {
369
+ throw new Error("AutoplayUser must be provided when enabling autoplay.");
373
370
  }
374
371
  this.autoplayTries = tries && typeof tries === "number" && tries > 0 ? tries : 3; // Default to 3 if invalid
375
372
  this.isAutoplay = true;
376
- this.set("Internal_BotUser", botUser);
373
+ this.set("Internal_AutoplayUser", AutoplayUser);
377
374
  }
378
375
  else {
379
376
  this.isAutoplay = false;
380
377
  this.autoplayTries = null;
381
- this.set("Internal_BotUser", null);
378
+ this.set("Internal_AutoplayUser", null);
382
379
  }
383
380
  const oldPlayer = { ...this };
384
381
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
@@ -852,7 +849,7 @@ class Player {
852
849
  queueRepeat: this.queueRepeat,
853
850
  dynamicRepeat: this.dynamicRepeat,
854
851
  dynamicRepeatIntervalMs: this.dynamicRepeatIntervalMs,
855
- ClientUser: this.get("Internal_BotUser"),
852
+ ClientUser: this.get("Internal_AutoplayUser"),
856
853
  filters: this.filters,
857
854
  nowPlayingMessage: this.nowPlayingMessage,
858
855
  isAutoplay: this.isAutoplay,
@@ -889,7 +886,7 @@ class Player {
889
886
  clonedPlayer.queueRepeat = oldPlayerProperties.queueRepeat;
890
887
  clonedPlayer.dynamicRepeat = oldPlayerProperties.dynamicRepeat;
891
888
  clonedPlayer.dynamicRepeatIntervalMs = oldPlayerProperties.dynamicRepeatIntervalMs;
892
- clonedPlayer.set("Internal_BotUser", oldPlayerProperties.ClientUser);
889
+ clonedPlayer.set("Internal_AutoplayUser", oldPlayerProperties.ClientUser);
893
890
  clonedPlayer.paused = oldPlayerProperties.paused;
894
891
  // Update filters for the cloned player
895
892
  await clonedPlayer.filters.updateFilters();
@@ -906,7 +903,7 @@ class Player {
906
903
  queueSize: clonedPlayer.queue.size,
907
904
  },
908
905
  };
909
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[PLAYER] Transferred player to a new server: ${JSON.stringify(debugInfo)}.`);
906
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[PLAYER] Transferred player to a new server: ${Utils_1.JSONUtils.safe(debugInfo, 2)}.`);
910
907
  // Return the cloned player
911
908
  return clonedPlayer;
912
909
  }
@@ -1035,7 +1032,7 @@ class Player {
1035
1032
  const packet = JSON.parse(payload);
1036
1033
  if (!packet?.op)
1037
1034
  return;
1038
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `VoiceReceiver recieved a payload: ${JSON.stringify(payload)}`);
1035
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `VoiceReceiver recieved a payload: ${Utils_1.JSONUtils.safe(payload, 2)}`);
1039
1036
  switch (packet.type) {
1040
1037
  case "startSpeakingEvent": {
1041
1038
  this.manager.emit(Enums_1.ManagerEventTypes.VoiceReceiverStartSpeaking, this, packet.data);
@@ -1050,7 +1047,7 @@ class Player {
1050
1047
  break;
1051
1048
  }
1052
1049
  default: {
1053
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `VoiceReceiver recieved an unknown payload: ${JSON.stringify(payload)}`);
1050
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `VoiceReceiver recieved an unknown payload: ${Utils_1.JSONUtils.safe(payload, 2)}`);
1054
1051
  break;
1055
1052
  }
1056
1053
  }
@@ -4,6 +4,7 @@ exports.Rest = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const axios_1 = tslib_1.__importDefault(require("axios"));
6
6
  const Enums_1 = require("./Enums");
7
+ const Utils_1 = require("./Utils");
7
8
  /** Handles the requests sent to the Lavalink REST API. */
8
9
  class Rest {
9
10
  /** The Node that this Rest instance is connected to. */
@@ -44,7 +45,7 @@ class Rest {
44
45
  // Send a GET request to the Lavalink Node to retrieve all the players.
45
46
  const result = await this.get(`/v4/sessions/${this.sessionId}/players`);
46
47
  // Log the result of the request.
47
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Getting all players on node: ${this.node.options.identifier} : ${JSON.stringify(result)}`);
48
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Getting all players on node: ${this.node.options.identifier} : ${Utils_1.JSONUtils.safe(result, 2)}`);
48
49
  // Return the result of the request.
49
50
  return result;
50
51
  }
@@ -55,7 +56,7 @@ class Rest {
55
56
  */
56
57
  async updatePlayer(options) {
57
58
  // Log the request.
58
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Updating player: ${options.guildId}: ${JSON.stringify(options)}`);
59
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Updating player: ${options.guildId}: ${Utils_1.JSONUtils.safe(options, 2)}`);
59
60
  // Send the PATCH request.
60
61
  return await this.patch(`/v4/sessions/${this.sessionId}/players/${options.guildId}?noReplace=false`, options.data);
61
62
  }
@@ -92,7 +93,7 @@ class Rest {
92
93
  * @returns {Promise<unknown>} The response data of the request.
93
94
  */
94
95
  async request(method, endpoint, body) {
95
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] ${method} api call for endpoint: ${endpoint} with data: ${JSON.stringify(body)}`);
96
+ this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] ${method} api call for endpoint: ${endpoint} with data: ${Utils_1.JSONUtils.safe(body, 2)}`);
96
97
  const config = {
97
98
  method,
98
99
  url: this.url + endpoint,
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Structure = exports.PlayerUtils = exports.AutoPlayUtils = exports.TrackUtils = void 0;
3
+ exports.JSONUtils = exports.Structure = exports.PlayerUtils = exports.AutoPlayUtils = exports.TrackUtils = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  /* eslint-disable @typescript-eslint/no-require-imports */
6
6
  const axios_1 = tslib_1.__importDefault(require("axios"));
7
7
  const jsdom_1 = require("jsdom");
8
8
  const Enums_1 = require("./Enums");
9
9
  const path_1 = tslib_1.__importDefault(require("path"));
10
+ const safe_stable_stringify_1 = tslib_1.__importDefault(require("safe-stable-stringify"));
10
11
  // import playwright from "playwright";
11
12
  /** @hidden */
12
13
  const SIZES = ["0", "1", "2", "3", "default", "mqdefault", "hqdefault", "maxresdefault"];
@@ -601,58 +602,52 @@ class PlayerUtils {
601
602
  * @returns The serialized Player instance
602
603
  */
603
604
  static async serializePlayer(player) {
604
- const seen = new WeakSet();
605
- // Fetch async queue data once before serializing
606
605
  const current = await player.queue.getCurrent();
607
606
  const tracks = Array.isArray(await player.queue.getTracks()) ? await player.queue.getTracks() : [];
608
607
  const previous = Array.isArray(await player.queue.getPrevious()) ? await player.queue.getPrevious() : [];
609
- /**
610
- * Recursively serializes an object, avoiding circular references.
611
- * @param obj The object to serialize
612
- * @returns The serialized object
613
- */
614
- const serialize = (obj) => {
615
- if (obj && typeof obj === "object") {
616
- if (seen.has(obj))
608
+ const seen = new WeakSet();
609
+ // The replacer function
610
+ const replacer = (key, value) => {
611
+ if (value && typeof value === "object") {
612
+ if (seen.has(value))
617
613
  return;
618
- seen.add(obj);
614
+ seen.add(value);
619
615
  }
620
- return obj;
621
- };
622
- return JSON.parse(JSON.stringify(player, (key, value) => {
623
- if (key === "manager") {
616
+ if (key === "manager")
624
617
  return null;
625
- }
626
618
  if (key === "filters") {
627
619
  if (!value || typeof value !== "object")
628
620
  return null;
621
+ const filters = value;
629
622
  return {
630
- distortion: value.distortion ?? null,
631
- equalizer: value.equalizer ?? [],
632
- karaoke: value.karaoke ?? null,
633
- rotation: value.rotation ?? null,
634
- timescale: value.timescale ?? null,
635
- vibrato: value.vibrato ?? null,
636
- reverb: value.reverb ?? null,
637
- volume: value.volume ?? 1.0,
638
- bassBoostlevel: value.bassBoostlevel ?? null,
639
- filterStatus: value.filtersStatus ? { ...value.filtersStatus } : {},
623
+ distortion: filters.distortion ?? null,
624
+ equalizer: filters.equalizer ?? [],
625
+ karaoke: filters.karaoke ?? null,
626
+ rotation: filters.rotation ?? null,
627
+ timescale: filters.timescale ?? null,
628
+ vibrato: filters.vibrato ?? null,
629
+ reverb: filters.reverb ?? null,
630
+ volume: filters.volume ?? 1.0,
631
+ bassBoostlevel: filters.bassBoostlevel ?? null,
632
+ filterStatus: filters.filtersStatus ? { ...filters.filtersStatus } : {},
640
633
  };
641
634
  }
642
635
  if (key === "queue") {
643
- return {
644
- current,
645
- tracks,
646
- previous,
647
- };
636
+ return { current, tracks, previous };
648
637
  }
649
638
  if (key === "data") {
639
+ const data = value;
640
+ const AutoplayUser = data?.Internal_AutoplayUser;
641
+ const serializedUser = AutoplayUser ? { id: AutoplayUser.id, username: AutoplayUser.username } : null;
650
642
  return {
651
- clientUser: value?.Internal_BotUser ?? null,
643
+ clientUser: serializedUser,
644
+ autoplayTries: data?.autoplayTries ?? null,
652
645
  };
653
646
  }
654
- return serialize(value);
655
- }));
647
+ return value;
648
+ };
649
+ const jsonString = (0, safe_stable_stringify_1.default)(player, replacer, 2);
650
+ return JSON.parse(jsonString);
656
651
  }
657
652
  /**
658
653
  * Gets the base directory for player data.
@@ -718,6 +713,12 @@ class Structure {
718
713
  }
719
714
  }
720
715
  exports.Structure = Structure;
716
+ class JSONUtils {
717
+ static safe(obj, space) {
718
+ return (0, safe_stable_stringify_1.default)(obj, null, space);
719
+ }
720
+ }
721
+ exports.JSONUtils = JSONUtils;
721
722
  const structures = {
722
723
  Player: require("./Player").Player,
723
724
  Queue: require("../statestorage/MemoryQueue").MemoryQueue,
@@ -32,5 +32,21 @@ class DetritusManager extends Manager_1.Manager {
32
32
  shard.gateway.send(packet.op, packet.d);
33
33
  }
34
34
  }
35
+ async resolveUser(user) {
36
+ const id = typeof user === "string" ? user : user.id;
37
+ if (this.client instanceof detritus_client_1.ShardClient) {
38
+ const cached = this.client.users.get(id);
39
+ if (cached)
40
+ return { id: cached.id, username: cached.username };
41
+ }
42
+ else if (this.client instanceof detritus_client_1.ClusterClient) {
43
+ for (const [, shard] of this.client.shards) {
44
+ const cached = shard.users.get(id);
45
+ if (cached)
46
+ return { id: cached.id, username: cached.username };
47
+ }
48
+ }
49
+ return typeof user === "string" ? { id: user } : user;
50
+ }
35
51
  }
36
52
  exports.DetritusManager = DetritusManager;
@@ -38,5 +38,18 @@ class DiscordJSManager extends Manager_1.Manager {
38
38
  if (guild)
39
39
  guild.shard.send(packet);
40
40
  }
41
+ async resolveUser(user) {
42
+ const id = typeof user === "string" ? user : user.id;
43
+ const cached = this.client.users.cache.get(id);
44
+ if (cached)
45
+ return cached;
46
+ try {
47
+ const fetched = await this.client.users.fetch(id);
48
+ return fetched;
49
+ }
50
+ catch {
51
+ return { id, username: typeof user === "string" ? undefined : user.username };
52
+ }
53
+ }
41
54
  }
42
55
  exports.DiscordJSManager = DiscordJSManager;
@@ -25,5 +25,15 @@ class ErisManager extends Manager_1.Manager {
25
25
  if (guild)
26
26
  guild.shard.sendWS(packet.op, packet.d);
27
27
  }
28
+ async resolveUser(user) {
29
+ const id = typeof user === "string" ? user : user.id;
30
+ const cached = this.client.users.get(id);
31
+ if (cached)
32
+ return cached;
33
+ return {
34
+ id,
35
+ username: typeof user === "string" ? undefined : user.username,
36
+ };
37
+ }
28
38
  }
29
39
  exports.ErisManager = ErisManager;
@@ -25,5 +25,15 @@ class OceanicManager extends Manager_1.Manager {
25
25
  if (guild)
26
26
  guild.shard.send(packet.op, packet.d);
27
27
  }
28
+ async resolveUser(user) {
29
+ const id = typeof user === "string" ? user : user.id;
30
+ const cached = this.client.users.get(id);
31
+ if (cached)
32
+ return cached;
33
+ return {
34
+ id,
35
+ username: typeof user === "string" ? undefined : user.username,
36
+ };
37
+ }
28
38
  }
29
39
  exports.OceanicManager = OceanicManager;
@@ -38,11 +38,23 @@ class SeyfertManager extends Manager_1.Manager {
38
38
  this.client = client;
39
39
  }
40
40
  send(packet) {
41
- if (this.client instanceof seyfert_1.WorkerClient) {
42
- this.client.shards.get((0, common_1.calculateShardId)(packet.d.guild_id))?.send(true, packet);
41
+ if (this.client instanceof seyfert_1.Client) {
42
+ this.client.gateway.send((0, common_1.calculateShardId)(packet.d.guild_id), packet);
43
43
  }
44
44
  else {
45
- this.client.gateway.send((0, common_1.calculateShardId)(packet.d.guild_id), packet);
45
+ this.client.shards.get((0, common_1.calculateShardId)(packet.d.guild_id))?.send(true, packet);
46
+ }
47
+ }
48
+ async resolveUser(user) {
49
+ const id = typeof user === "string" ? user : user.id;
50
+ const cached = this.client.cache.users?.get(id);
51
+ if (cached)
52
+ return cached;
53
+ try {
54
+ return await this.client.users.fetch(id);
55
+ }
56
+ catch {
57
+ return { id, username: typeof user === "string" ? undefined : user.username };
46
58
  }
47
59
  }
48
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magmastream",
3
- "version": "2.9.1-dev.2",
3
+ "version": "2.9.1-dev.4",
4
4
  "description": "A user-friendly Lavalink client designed for NodeJS.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,6 +35,7 @@
35
35
  "ioredis": "^5.6.1",
36
36
  "jsdom": "^26.1.0",
37
37
  "lodash": "^4.17.21",
38
+ "safe-stable-stringify": "^2.5.0",
38
39
  "tslib": "^2.8.1",
39
40
  "ws": "^8.18.3"
40
41
  },