magmastream 2.9.3-dev.3 → 2.9.3-dev.31

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.
Files changed (42) hide show
  1. package/dist/config/blockedWords.d.ts +1 -0
  2. package/dist/index.d.ts +19 -3687
  3. package/dist/index.js +1 -1
  4. package/dist/statestorage/JsonQueue.d.ts +173 -0
  5. package/dist/statestorage/JsonQueue.js +32 -4
  6. package/dist/statestorage/MemoryQueue.d.ts +154 -0
  7. package/dist/statestorage/MemoryQueue.js +56 -36
  8. package/dist/statestorage/RedisQueue.d.ts +178 -0
  9. package/dist/statestorage/RedisQueue.js +29 -7
  10. package/dist/structures/Enums.d.ts +310 -0
  11. package/dist/structures/Enums.js +6 -0
  12. package/dist/structures/Filters.d.ts +352 -0
  13. package/dist/structures/Filters.js +5 -4
  14. package/dist/structures/MagmastreamError.d.ts +14 -0
  15. package/dist/structures/Manager.d.ts +259 -0
  16. package/dist/structures/Manager.js +296 -555
  17. package/dist/structures/Node.d.ts +390 -0
  18. package/dist/structures/Node.js +100 -145
  19. package/dist/structures/Player.d.ts +347 -0
  20. package/dist/structures/Player.js +55 -132
  21. package/dist/structures/Plugin.d.ts +23 -0
  22. package/dist/structures/Rest.d.ts +93 -0
  23. package/dist/structures/Rest.js +41 -21
  24. package/dist/structures/Types.d.ts +1315 -0
  25. package/dist/structures/Utils.d.ts +169 -0
  26. package/dist/structures/Utils.js +145 -71
  27. package/dist/utils/filtersEqualizers.d.ts +16 -0
  28. package/dist/utils/managerCheck.d.ts +7 -0
  29. package/dist/utils/nodeCheck.d.ts +7 -0
  30. package/dist/utils/playerCheck.d.ts +7 -0
  31. package/dist/wrappers/discord.js.d.ts +15 -0
  32. package/dist/wrappers/discord.js.js +19 -4
  33. package/dist/wrappers/discordeno.d.ts +19 -0
  34. package/dist/wrappers/discordeno.js +77 -0
  35. package/dist/wrappers/eris.d.ts +15 -0
  36. package/dist/wrappers/eris.js +20 -3
  37. package/dist/wrappers/oceanic.d.ts +15 -0
  38. package/dist/wrappers/oceanic.js +22 -4
  39. package/dist/wrappers/seyfert.d.ts +37 -0
  40. package/dist/wrappers/seyfert.js +25 -1
  41. package/package.json +106 -98
  42. package/dist/wrappers/detritus.js +0 -52
@@ -0,0 +1,347 @@
1
+ import { Filters } from "./Filters";
2
+ import { Manager } from "./Manager";
3
+ import { Node } from "./Node";
4
+ import { AnyMessage, IQueue, Lyrics, PlayerOptions, PlayOptions, SearchQuery, SearchResult, Track, VoiceState } from "./Types";
5
+ import { SponsorBlockSegment, StateTypes } from "./Enums";
6
+ import { WebSocket } from "ws";
7
+ export declare class Player {
8
+ options: PlayerOptions;
9
+ /** The Queue for the Player. */
10
+ queue: IQueue;
11
+ /** The filters applied to the audio. */
12
+ filters: Filters;
13
+ /** Whether the queue repeats the track. */
14
+ trackRepeat: boolean;
15
+ /** Whether the queue repeats the queue. */
16
+ queueRepeat: boolean;
17
+ /**Whether the queue repeats and shuffles after each song. */
18
+ dynamicRepeat: boolean;
19
+ /** The time the player is in the track. */
20
+ position: number;
21
+ /** Whether the player is playing. */
22
+ playing: boolean;
23
+ /** Whether the player is paused. */
24
+ paused: boolean;
25
+ /** The volume for the player */
26
+ volume: number;
27
+ /** The Node for the Player. */
28
+ node: Node;
29
+ /** The guild ID for the player. */
30
+ guildId: string;
31
+ /** The voice channel for the player. */
32
+ voiceChannelId: string | null;
33
+ /** The text channel for the player. */
34
+ textChannelId: string | null;
35
+ /**The now playing message. */
36
+ nowPlayingMessage?: AnyMessage;
37
+ /** The current state of the player. */
38
+ state: StateTypes;
39
+ /** The equalizer bands array. */
40
+ bands: number[];
41
+ /** The voice state object from Discord. */
42
+ voiceState: VoiceState;
43
+ /** The Manager. */
44
+ manager: Manager;
45
+ /** The autoplay state of the player. */
46
+ isAutoplay: boolean;
47
+ /** The number of times to try autoplay before emitting queueEnd. */
48
+ autoplayTries: number;
49
+ /** The cluster ID for the player. */
50
+ clusterId: number;
51
+ private readonly data;
52
+ private dynamicLoopInterval;
53
+ dynamicRepeatIntervalMs: number | null;
54
+ private static _manager;
55
+ /** Should only be used when the node is a NodeLink */
56
+ protected voiceReceiverWsClient: WebSocket | null;
57
+ protected isConnectToVoiceReceiver: boolean;
58
+ protected voiceReceiverReconnectTimeout: NodeJS.Timeout | null;
59
+ protected voiceReceiverAttempt: number;
60
+ protected voiceReceiverReconnectTries: number;
61
+ /**
62
+ * Creates a new player, returns one if it already exists.
63
+ * @param options The player options.
64
+ * @see https://docs.magmastream.com/main/introduction/getting-started
65
+ */
66
+ constructor(options: PlayerOptions);
67
+ /**
68
+ * Initializes the static properties of the Player class.
69
+ * @hidden
70
+ * @param manager The Manager to use.
71
+ */
72
+ static init(manager: Manager): void;
73
+ /**
74
+ * Set custom data.
75
+ * @param key - The key to set the data for.
76
+ * @param value - The value to set the data to.
77
+ */
78
+ set(key: string, value: unknown): void;
79
+ /**
80
+ * Retrieves custom data associated with a given key.
81
+ * @template T - The expected type of the data.
82
+ * @param {string} key - The key to retrieve the data for.
83
+ * @returns {T} - The data associated with the key, cast to the specified type.
84
+ */
85
+ get<T>(key: string): T;
86
+ /**
87
+ * Same as Manager#search() but a shortcut on the player itself.
88
+ * @param query
89
+ * @param requester
90
+ */
91
+ search<T = unknown>(query: string | SearchQuery, requester?: T): Promise<SearchResult>;
92
+ /**
93
+ * Connects the player to the voice channel.
94
+ * @throws {RangeError} If no voice channel has been set.
95
+ * @returns {void}
96
+ */
97
+ connect(): void;
98
+ /**
99
+ * Disconnects the player from the voice channel.
100
+ * @returns {this} The player instance.
101
+ */
102
+ disconnect(): Promise<this>;
103
+ /**
104
+ * Destroys the player and clears the queue.
105
+ * @param {boolean} disconnect - Whether to disconnect the player from the voice channel.
106
+ * @returns {Promise<boolean>} - Whether the player was successfully destroyed.
107
+ * @emits {PlayerDestroy} - Emitted when the player is destroyed.
108
+ * @emits {PlayerStateUpdate} - Emitted when the player state is updated.
109
+ */
110
+ destroy(disconnect?: boolean): Promise<boolean>;
111
+ /**
112
+ * Sets the player voice channel.
113
+ * @param {string} channel - The new voice channel ID.
114
+ * @returns {this} - The player instance.
115
+ * @throws {TypeError} If the channel parameter is not a string.
116
+ */
117
+ setVoiceChannelId(channel: string): this;
118
+ /**
119
+ * Sets the player text channel.
120
+ *
121
+ * This method updates the text channel associated with the player. It also
122
+ * emits a player state update event indicating the change in the channel.
123
+ *
124
+ * @param {string} channel - The new text channel ID.
125
+ * @returns {this} - The player instance for method chaining.
126
+ * @throws {TypeError} If the channel parameter is not a string.
127
+ */
128
+ setTextChannelId(channel: string): this;
129
+ /**
130
+ * Sets the now playing message.
131
+ *
132
+ * @param message - The message of the now playing message.
133
+ * @returns The now playing message.
134
+ */
135
+ setNowPlayingMessage(message: AnyMessage): AnyMessage;
136
+ /**
137
+ * Plays the next track.
138
+ *
139
+ * If a track is provided, it will be played. Otherwise, the next track in the queue will be played.
140
+ * If the queue is not empty, but the current track has not finished yet, it will be replaced with the provided track.
141
+ *
142
+ * @param {object} [optionsOrTrack] - The track to play or the options to play with.
143
+ * @param {object} [playOptions] - The options to play with.
144
+ *
145
+ * @returns {Promise<void>}
146
+ */
147
+ play(): Promise<Player>;
148
+ play(track: Track): Promise<Player>;
149
+ play(options: PlayOptions): Promise<Player>;
150
+ play(track: Track, options: PlayOptions): Promise<Player>;
151
+ /**
152
+ * Sets the autoplay-state of the player.
153
+ *
154
+ * Autoplay is a feature that makes the player play a recommended
155
+ * track when the current track ends.
156
+ *
157
+ * @param {boolean} autoplayState - Whether or not autoplay should be enabled.
158
+ * @param {object} AutoplayUser - The user-object that should be used as the bot-user.
159
+ * @param {number} [tries=3] - The number of times the player should try to find a
160
+ * recommended track if the first one doesn't work.
161
+ * @returns {this} - The player instance.
162
+ */
163
+ setAutoplay<T = unknown>(autoplayState: boolean, AutoplayUser?: T, tries?: number): this;
164
+ /**
165
+ * Gets recommended tracks and returns an array of tracks.
166
+ * @param {Track} track - The track to find recommendations for.
167
+ * @returns {Promise<Track[]>} - Array of recommended tracks.
168
+ */
169
+ getRecommendedTracks(track: Track): Promise<Track[]>;
170
+ /**
171
+ * Sets the volume of the player.
172
+ * @param {number} volume - The new volume. Must be between 0 and 500 when using filter mode (100 = 100%).
173
+ * @returns {Promise<Player>} - The updated player.
174
+ * @throws {TypeError} If the volume is not a number.
175
+ * @throws {RangeError} If the volume is not between 0 and 500 when using filter mode (100 = 100%).
176
+ * @emits {PlayerStateUpdate} - Emitted when the volume is changed.
177
+ * @example
178
+ * player.setVolume(50);
179
+ */
180
+ setVolume(volume: number): Promise<this>;
181
+ /**
182
+ * Sets the sponsorblock for the player. This will set the sponsorblock segments for the player to the given segments.
183
+ * @param {SponsorBlockSegment[]} segments - The sponsorblock segments to set. Defaults to `[SponsorBlockSegment.Sponsor, SponsorBlockSegment.SelfPromo]` if not provided.
184
+ * @returns {Promise<void>} The promise is resolved when the operation is complete.
185
+ */
186
+ setSponsorBlock(segments?: SponsorBlockSegment[]): Promise<void>;
187
+ /**
188
+ * Gets the sponsorblock for the player.
189
+ * @returns {Promise<SponsorBlockSegment[]>} The sponsorblock segments.
190
+ */
191
+ getSponsorBlock(): Promise<SponsorBlockSegment[]>;
192
+ /**
193
+ * Deletes the sponsorblock for the player. This will remove all sponsorblock segments that have been set for the player.
194
+ * @returns {Promise<void>}
195
+ */
196
+ deleteSponsorBlock(): Promise<void>;
197
+ /**
198
+ * Sets the track repeat mode.
199
+ * When track repeat is enabled, the current track will replay after it ends.
200
+ * Disables queueRepeat and dynamicRepeat modes if enabled.
201
+ *
202
+ * @param repeat - A boolean indicating whether to enable track repeat.
203
+ * @returns {this} - The player instance.
204
+ * @throws {TypeError} If the repeat parameter is not a boolean.
205
+ */
206
+ setTrackRepeat(repeat: boolean): this;
207
+ /**
208
+ * Sets the queue repeat.
209
+ * @param repeat Whether to repeat the queue or not
210
+ * @returns {this} - The player instance.
211
+ * @throws {TypeError} If the repeat parameter is not a boolean
212
+ */
213
+ setQueueRepeat(repeat: boolean): this;
214
+ /**
215
+ * Sets the queue to repeat and shuffles the queue after each song.
216
+ * @param repeat "true" or "false".
217
+ * @param ms After how many milliseconds to trigger dynamic repeat.
218
+ * @returns {this} - The player instance.
219
+ * @throws {TypeError} If the repeat parameter is not a boolean.
220
+ * @throws {RangeError} If the queue size is less than or equal to 1.
221
+ */
222
+ setDynamicRepeat(repeat: boolean, ms: number): Promise<this>;
223
+ /**
224
+ * Restarts the currently playing track from the beginning.
225
+ * If there is no track playing, it will play the next track in the queue.
226
+ * @returns {Promise<Player>} The current instance of the Player class for method chaining.
227
+ */
228
+ restart(): Promise<Player>;
229
+ /**
230
+ * Stops the player and optionally removes tracks from the queue.
231
+ * @param {number} [amount] The amount of tracks to remove from the queue. If not provided, removes the current track if it exists.
232
+ * @returns {Promise<this>} - The player instance.
233
+ * @throws {RangeError} If the amount is greater than the queue length.
234
+ */
235
+ stop(amount?: number): Promise<this>;
236
+ /**
237
+ * Skips the current track.
238
+ * @returns {this} - The player instance.
239
+ * @throws {Error} If there are no tracks in the queue.
240
+ * @emits {PlayerStateUpdate} - With {@link PlayerStateEventTypes.TrackChange} as the change type.
241
+ */
242
+ pause(pause: boolean): Promise<this>;
243
+ /**
244
+ * Skips to the previous track in the queue.
245
+ * @returns {this} - The player instance.
246
+ * @throws {Error} If there are no previous tracks in the queue.
247
+ * @emits {PlayerStateUpdate} - With {@link PlayerStateEventTypes.TrackChange} as the change type.
248
+ */
249
+ previous(addBackToQueue?: boolean): Promise<this>;
250
+ /**
251
+ * Seeks to a given position in the currently playing track.
252
+ * @param position - The position in milliseconds to seek to.
253
+ * @returns {this} - The player instance.
254
+ * @throws {Error} If the position is invalid.
255
+ * @emits {PlayerStateUpdate} - With {@link PlayerStateEventTypes.TrackChange} as the change type.
256
+ */
257
+ seek(position: number): Promise<this>;
258
+ /**
259
+ * Returns the current repeat state of the player.
260
+ * @param player The player to get the repeat state from.
261
+ * @returns The repeat state of the player, or null if it is not repeating.
262
+ */
263
+ private getRepeatState;
264
+ /**
265
+ * Automatically moves the player to a usable node.
266
+ * @returns {Promise<Player | void>} - The player instance or void if not moved.
267
+ */
268
+ autoMoveNode(): Promise<Player | void>;
269
+ /**
270
+ * Moves the player to another node.
271
+ * @param {string} identifier - The identifier of the node to move to.
272
+ * @returns {Promise<Player>} - The player instance after being moved.
273
+ */
274
+ moveNode(identifier: string): Promise<Player>;
275
+ /**
276
+ * Retrieves the data associated with the player.
277
+ * @returns {Record<string, unknown>} - The data associated with the player.
278
+ */
279
+ getData(): Record<string, unknown>;
280
+ /**
281
+ * Retrieves the dynamic loop interval of the player.
282
+ * @returns {NodeJS.Timeout | null} - The dynamic loop interval of the player.
283
+ */
284
+ getDynamicLoopIntervalPublic(): NodeJS.Timeout | null;
285
+ /**
286
+ * Retrieves the data associated with the player.
287
+ * @returns {Record<string, unknown>} - The data associated with the player.
288
+ */
289
+ getSerializableData(): Record<string, unknown>;
290
+ /**
291
+ * Retrieves the current lyrics for the playing track.
292
+ * @param skipTrackSource - Indicates whether to skip the track source when fetching lyrics.
293
+ * @returns {Promise<Lyrics>} - The lyrics of the current track.
294
+ */
295
+ getCurrentLyrics(skipTrackSource?: boolean): Promise<Lyrics>;
296
+ /**
297
+ * Sets up the voice receiver for the player.
298
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver is set up.
299
+ * @throws {Error} - If the node is not a NodeLink.
300
+ */
301
+ setupVoiceReceiver(): Promise<void>;
302
+ /**
303
+ * Removes the voice receiver for the player.
304
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver is removed.
305
+ * @throws {Error} - If the node is not a NodeLink.
306
+ */
307
+ removeVoiceReceiver(): Promise<void>;
308
+ /**
309
+ * Closes the voice receiver for the player.
310
+ * @param {number} code - The code to close the voice receiver with.
311
+ * @param {string} reason - The reason to close the voice receiver with.
312
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver is closed.
313
+ */
314
+ private closeVoiceReceiver;
315
+ /**
316
+ * Reconnects the voice receiver for the player.
317
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver is reconnected.
318
+ */
319
+ private reconnectVoiceReceiver;
320
+ /**
321
+ * Disconnects the voice receiver for the player.
322
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver is disconnected.
323
+ */
324
+ private disconnectVoiceReceiver;
325
+ /**
326
+ * Opens the voice receiver for the player.
327
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver is opened.
328
+ */
329
+ private openVoiceReceiver;
330
+ /**
331
+ * Handles a voice receiver message.
332
+ * @param {string} payload - The payload to handle.
333
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver message is handled.
334
+ */
335
+ private onVoiceReceiverMessage;
336
+ /**
337
+ * Handles a voice receiver error.
338
+ * @param {Error} error - The error to handle.
339
+ * @returns {Promise<void>} - A promise that resolves when the voice receiver error is handled.
340
+ */
341
+ private onVoiceReceiverError;
342
+ /**
343
+ * Updates the voice state for the player.
344
+ * @returns {Promise<void>} - A promise that resolves when the voice state is updated.
345
+ */
346
+ updateVoice(): Promise<void>;
347
+ }
@@ -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 = {
@@ -260,21 +260,30 @@ class Player {
260
260
  */
261
261
  async destroy(disconnect = true) {
262
262
  this.state = Enums_1.StateTypes.Destroying;
263
+ if (this.dynamicLoopInterval) {
264
+ clearInterval(this.dynamicLoopInterval);
265
+ this.dynamicLoopInterval = null;
266
+ }
267
+ if (this.voiceReceiverReconnectTimeout) {
268
+ clearTimeout(this.voiceReceiverReconnectTimeout);
269
+ this.voiceReceiverReconnectTimeout = null;
270
+ }
271
+ if (this.voiceReceiverWsClient) {
272
+ this.voiceReceiverWsClient.removeAllListeners();
273
+ this.voiceReceiverWsClient.close();
274
+ this.voiceReceiverWsClient = null;
275
+ }
263
276
  if (disconnect) {
264
- await this.disconnect().catch((err) => {
265
- console.warn(`[Player#destroy] Failed to disconnect player ${this.guildId}:`, err);
266
- });
277
+ await this.disconnect().catch(() => { });
267
278
  }
268
- await this.node.rest.destroyPlayer(this.guildId).catch((err) => {
269
- console.warn(`[Player#destroy] REST failed to destroy player ${this.guildId}:`, err);
270
- });
271
- await this.queue.clear();
272
- await this.queue.clearPrevious();
273
- await this.queue.setCurrent(null);
279
+ await this.node.rest.destroyPlayer(this.guildId).catch(() => { });
280
+ await this.queue.destroy();
281
+ this.nowPlayingMessage = undefined;
274
282
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerDestroy, this);
275
283
  const deleted = this.manager.players.delete(this.guildId);
276
- if (this.manager.options.stateStorage.deleteInactivePlayers)
284
+ if (this.manager.options.stateStorage.deleteDestroyedPlayers) {
277
285
  await this.manager.cleanupInactivePlayer(this.guildId);
286
+ }
278
287
  return deleted;
279
288
  }
280
289
  /**
@@ -374,11 +383,8 @@ class Player {
374
383
  console.error(error);
375
384
  return this;
376
385
  }
377
- const finalOptions = playOptions
378
- ? playOptions
379
- : ["startTime", "endTime", "noReplace"].every((v) => Object.keys(optionsOrTrack || {}).includes(v))
380
- ? optionsOrTrack
381
- : {};
386
+ const isPlayOptions = (v) => typeof v === "object" && v !== null && ("startTime" in v || "endTime" in v || "noReplace" in v);
387
+ const finalOptions = playOptions ? playOptions : isPlayOptions(optionsOrTrack) ? optionsOrTrack : {};
382
388
  await this.node.rest.updatePlayer({
383
389
  guildId: this.guildId,
384
390
  data: {
@@ -387,7 +393,7 @@ class Player {
387
393
  },
388
394
  });
389
395
  this.playing = true;
390
- this.position = 0;
396
+ this.position = finalOptions.startTime || 0;
391
397
  return this;
392
398
  }
393
399
  /**
@@ -806,11 +812,8 @@ class Player {
806
812
  if (currentPlayingTrack) {
807
813
  await this.queue.add(currentPlayingTrack, 0);
808
814
  }
809
- await this.play(lastTrack);
810
- }
811
- else {
812
- await this.play(lastTrack);
813
815
  }
816
+ await this.play(lastTrack);
814
817
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
815
818
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
816
819
  details: {
@@ -922,7 +925,8 @@ class Player {
922
925
  const sessionId = this.voiceState?.sessionId;
923
926
  const token = this.voiceState?.event?.token;
924
927
  const endpoint = this.voiceState?.event?.endpoint;
925
- if (!sessionId || !token || !endpoint) {
928
+ const channelId = this.voiceState?.channelId;
929
+ if (!sessionId || !token || !endpoint || !channelId) {
926
930
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Voice state is not properly initialized for player ${this.guildId}. The bot might not be connected to a voice channel.`);
927
931
  throw new MagmastreamError_1.MagmaStreamError({
928
932
  code: Enums_1.MagmaStreamErrorCode.PLAYER_STATE_INVALID,
@@ -936,7 +940,7 @@ class Player {
936
940
  this.manager.players.set(this.guildId, this);
937
941
  await this.node.rest.updatePlayer({
938
942
  guildId: this.guildId,
939
- data: { paused: this.paused, volume: this.volume, position: playerPosition, encodedTrack: currentTrack?.track, voice: { token, endpoint, sessionId } },
943
+ data: { paused: this.paused, volume: this.volume, position: playerPosition, encodedTrack: currentTrack?.track, voice: { token, endpoint, sessionId, channelId } },
940
944
  });
941
945
  await this.filters.updateFilters();
942
946
  }
@@ -953,115 +957,6 @@ class Player {
953
957
  console.error(error);
954
958
  }
955
959
  }
956
- /**
957
- * Transfers the player to a new server. If the player already exists on the new server
958
- * and force is false, this method will return the existing player. Otherwise, a new player
959
- * will be created and the current player will be destroyed.
960
- * @param {PlayerOptions} newOptions - The new options for the player.
961
- * @param {boolean} force - Whether to force the creation of a new player.
962
- * @returns {Promise<Player>} - The new player instance.
963
- */
964
- async switchGuild(newOptions, force = false) {
965
- if (!newOptions.guildId) {
966
- throw new MagmastreamError_1.MagmaStreamError({
967
- code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
968
- message: "guildId is required for switchGuild",
969
- });
970
- }
971
- if (!newOptions.voiceChannelId) {
972
- throw new MagmastreamError_1.MagmaStreamError({
973
- code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
974
- message: "voiceChannelId is required for switchGuild",
975
- });
976
- }
977
- if (!newOptions.textChannelId) {
978
- throw new MagmastreamError_1.MagmaStreamError({
979
- code: Enums_1.MagmaStreamErrorCode.PLAYER_INVALID_CONFIG,
980
- message: "textChannelId is required for switchGuild",
981
- });
982
- }
983
- // Check if a player already exists for the new guild
984
- let newPlayer = this.manager.getPlayer(newOptions.guildId);
985
- // If the player already exists and force is false, return the existing player
986
- if (newPlayer && !force)
987
- return newPlayer;
988
- const oldPlayerProperties = {
989
- paused: this.paused,
990
- selfMute: this.options.selfMute,
991
- selfDeafen: this.options.selfDeafen,
992
- volume: this.volume,
993
- position: this.position,
994
- queue: {
995
- current: await this.queue.getCurrent(),
996
- tracks: [...(await this.queue.getTracks())],
997
- previous: [...(await this.queue.getPrevious())],
998
- },
999
- trackRepeat: this.trackRepeat,
1000
- queueRepeat: this.queueRepeat,
1001
- dynamicRepeat: this.dynamicRepeat,
1002
- dynamicRepeatIntervalMs: this.dynamicRepeatIntervalMs,
1003
- ClientUser: this.get("Internal_AutoplayUser"),
1004
- filters: this.filters,
1005
- nowPlayingMessage: this.nowPlayingMessage,
1006
- isAutoplay: this.isAutoplay,
1007
- applyVolumeAsFilter: this.options.applyVolumeAsFilter,
1008
- pauseOnDisconnect: this.options.pauseOnDisconnect,
1009
- };
1010
- // If force is true, destroy the existing player for the new guild
1011
- if (force && newPlayer) {
1012
- await newPlayer.destroy();
1013
- }
1014
- newOptions.nodeIdentifier = newOptions.nodeIdentifier ?? this.options.nodeIdentifier;
1015
- newOptions.selfDeafen = newOptions.selfDeafen ?? oldPlayerProperties.selfDeafen;
1016
- newOptions.selfMute = newOptions.selfMute ?? oldPlayerProperties.selfMute;
1017
- newOptions.volume = newOptions.volume ?? oldPlayerProperties.volume;
1018
- newOptions.applyVolumeAsFilter = newOptions.applyVolumeAsFilter ?? oldPlayerProperties.applyVolumeAsFilter;
1019
- newOptions.pauseOnDisconnect = newOptions.pauseOnDisconnect ?? oldPlayerProperties.pauseOnDisconnect;
1020
- // Deep clone the current player
1021
- const clonedPlayer = this.manager.create(newOptions);
1022
- // Connect the cloned player to the new voice channel
1023
- clonedPlayer.connect();
1024
- // Update the player's state on the Lavalink node
1025
- await clonedPlayer.node.rest.updatePlayer({
1026
- guildId: clonedPlayer.guildId,
1027
- data: {
1028
- paused: oldPlayerProperties.paused,
1029
- volume: oldPlayerProperties.volume,
1030
- position: oldPlayerProperties.position,
1031
- encodedTrack: oldPlayerProperties.queue.current?.track,
1032
- },
1033
- });
1034
- await clonedPlayer.queue.setCurrent(oldPlayerProperties.queue.current);
1035
- await clonedPlayer.queue.addPrevious(oldPlayerProperties.queue.previous);
1036
- await clonedPlayer.queue.add(oldPlayerProperties.queue.tracks);
1037
- clonedPlayer.filters = oldPlayerProperties.filters;
1038
- clonedPlayer.isAutoplay = oldPlayerProperties.isAutoplay;
1039
- clonedPlayer.nowPlayingMessage = oldPlayerProperties.nowPlayingMessage;
1040
- clonedPlayer.trackRepeat = oldPlayerProperties.trackRepeat;
1041
- clonedPlayer.queueRepeat = oldPlayerProperties.queueRepeat;
1042
- clonedPlayer.dynamicRepeat = oldPlayerProperties.dynamicRepeat;
1043
- clonedPlayer.dynamicRepeatIntervalMs = oldPlayerProperties.dynamicRepeatIntervalMs;
1044
- clonedPlayer.set("Internal_AutoplayUser", oldPlayerProperties.ClientUser);
1045
- clonedPlayer.paused = oldPlayerProperties.paused;
1046
- // Update filters for the cloned player
1047
- await clonedPlayer.filters.updateFilters();
1048
- // Debug information
1049
- const debugInfo = {
1050
- success: true,
1051
- message: `Transferred ${await clonedPlayer.queue.size()} tracks successfully to <#${newOptions.voiceChannelId}> bound to <#${newOptions.textChannelId}>.`,
1052
- player: {
1053
- guildId: clonedPlayer.guildId,
1054
- voiceChannelId: clonedPlayer.voiceChannelId,
1055
- textChannelId: clonedPlayer.textChannelId,
1056
- volume: clonedPlayer.volume,
1057
- playing: clonedPlayer.playing,
1058
- queueSize: clonedPlayer.queue.size,
1059
- },
1060
- };
1061
- this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[PLAYER] Transferred player to a new server: ${Utils_1.JSONUtils.safe(debugInfo, 2)}.`);
1062
- // Return the cloned player
1063
- return clonedPlayer;
1064
- }
1065
960
  /**
1066
961
  * Retrieves the data associated with the player.
1067
962
  * @returns {Record<string, unknown>} - The data associated with the player.
@@ -1076,6 +971,13 @@ class Player {
1076
971
  getDynamicLoopIntervalPublic() {
1077
972
  return this.dynamicLoopInterval;
1078
973
  }
974
+ /**
975
+ * Retrieves the data associated with the player.
976
+ * @returns {Record<string, unknown>} - The data associated with the player.
977
+ */
978
+ getSerializableData() {
979
+ return { ...this.data };
980
+ }
1079
981
  /**
1080
982
  * Retrieves the current lyrics for the playing track.
1081
983
  * @param skipTrackSource - Indicates whether to skip the track source when fetching lyrics.
@@ -1239,5 +1141,26 @@ class Player {
1239
1141
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `VoiceReceiver error for player ${this.guildId}: ${error.message}`);
1240
1142
  this.manager.emit(Enums_1.ManagerEventTypes.VoiceReceiverError, this, error);
1241
1143
  }
1144
+ /**
1145
+ * Updates the voice state for the player.
1146
+ * @returns {Promise<void>} - A promise that resolves when the voice state is updated.
1147
+ */
1148
+ async updateVoice() {
1149
+ const vs = this.voiceState;
1150
+ const ev = vs?.event;
1151
+ if (!vs?.channelId || !vs?.sessionId || !ev?.token || !ev?.endpoint)
1152
+ return;
1153
+ await this.node.rest.updatePlayer({
1154
+ guildId: this.options.guildId,
1155
+ data: {
1156
+ voice: {
1157
+ token: ev.token,
1158
+ endpoint: ev.endpoint,
1159
+ sessionId: vs.sessionId,
1160
+ channelId: vs.channelId,
1161
+ },
1162
+ },
1163
+ });
1164
+ }
1242
1165
  }
1243
1166
  exports.Player = Player;
@@ -0,0 +1,23 @@
1
+ import { Manager } from "./Manager";
2
+ /**
3
+ * Base abstract class for all plugins.
4
+ * Users must extend this and implement load and unload methods.
5
+ */
6
+ export declare abstract class Plugin {
7
+ readonly name: string;
8
+ /**
9
+ * @param name The name of the plugin
10
+ */
11
+ constructor(name: string);
12
+ /**
13
+ * Load the plugin.
14
+ * @param manager The MagmaStream Manager instance
15
+ */
16
+ abstract load(manager: Manager): void;
17
+ /**
18
+ * Unload the plugin.
19
+ * Called on shutdown to gracefully cleanup resources or detach listeners.
20
+ * @param manager The MagmaStream Manager instance
21
+ */
22
+ abstract unload(manager: Manager): void;
23
+ }