lavacord 3.0.1 → 3.1.0
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/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +6 -0
- package/dist/cjs/lib/Manager.cjs +3 -2
- package/dist/cjs/lib/Manager.cjs.map +1 -1
- package/dist/cjs/lib/Player.cjs +2 -1
- package/dist/cjs/lib/Player.cjs.map +1 -1
- package/dist/esm/index.d.mts +6 -0
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/lib/Manager.mjs +3 -2
- package/dist/esm/lib/Manager.mjs.map +1 -1
- package/dist/esm/lib/Player.mjs +2 -1
- package/dist/esm/lib/Player.mjs.map +1 -1
- package/package.json +8 -8
package/dist/cjs/index.cjs
CHANGED
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;AAYO,IAAM,OAAA,GAAkB","file":"index.cjs","sourcesContent":["/**\n * @module Lavacord\n */\nexport * from \"./lib/LavalinkNode\";\nexport * from \"./lib/Player\";\nexport * from \"./lib/Manager\";\nexport * from \"./lib/Rest\";\nexport * from \"./lib/Types\";\n\n// This is a placeholder for the version of the library, which should be injected during build time\n// this need to be explicitly typed as string.\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const VERSION: string = \"3.0
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;AAYO,IAAM,OAAA,GAAkB","file":"index.cjs","sourcesContent":["/**\n * @module Lavacord\n */\nexport * from \"./lib/LavalinkNode\";\nexport * from \"./lib/Player\";\nexport * from \"./lib/Manager\";\nexport * from \"./lib/Rest\";\nexport * from \"./lib/Types\";\n\n// This is a placeholder for the version of the library, which should be injected during build time\n// this need to be explicitly typed as string.\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const VERSION: string = \"3.1.0\";\n"]}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -27,6 +27,12 @@ interface PlayerUpdateVoiceState {
|
|
|
27
27
|
* @readonly
|
|
28
28
|
*/
|
|
29
29
|
event: GatewayVoiceServerUpdateDispatchData;
|
|
30
|
+
/**
|
|
31
|
+
* The ID of the voice channel.
|
|
32
|
+
*
|
|
33
|
+
* @readonly
|
|
34
|
+
*/
|
|
35
|
+
channelId: string;
|
|
30
36
|
}
|
|
31
37
|
/**
|
|
32
38
|
* Defines the options for configuring the Lavacord Manager.
|
package/dist/cjs/lib/Manager.cjs
CHANGED
|
@@ -251,13 +251,14 @@ var Manager = class extends events.EventEmitter {
|
|
|
251
251
|
*/
|
|
252
252
|
async switch(player, node) {
|
|
253
253
|
player.node = node;
|
|
254
|
-
if (!player.voice) return player;
|
|
254
|
+
if (!player.voice?.channelId) return player;
|
|
255
255
|
await player.destroy();
|
|
256
256
|
if (!player.track) return player;
|
|
257
257
|
await player.play(player.track.encoded, {
|
|
258
258
|
position: player.state.position,
|
|
259
259
|
volume: player.volume,
|
|
260
260
|
filters: player.filters,
|
|
261
|
+
// @ts-expect-error The type narrow for if no channelId didn't work
|
|
261
262
|
voice: player.voice,
|
|
262
263
|
paused: player.paused,
|
|
263
264
|
userData: player.track.userData
|
|
@@ -370,7 +371,7 @@ var Manager = class extends events.EventEmitter {
|
|
|
370
371
|
if (!server || !state || !this.expecting.has(guildID)) return false;
|
|
371
372
|
const player = this.players.get(guildID);
|
|
372
373
|
if (!player) return false;
|
|
373
|
-
await player.connect({ sessionId: state.session_id, event: server });
|
|
374
|
+
await player.connect({ sessionId: state.session_id, event: server, channelId: state.channel_id });
|
|
374
375
|
this.expecting.delete(guildID);
|
|
375
376
|
return true;
|
|
376
377
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/Manager.ts"],"names":["EventEmitter","Player","LavalinkNode"],"mappings":"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","file":"Manager.cjs","sourcesContent":["import { EventEmitter } from \"events\";\nimport { LavalinkNode } from \"./LavalinkNode\";\nimport { Player } from \"./Player\";\nimport type { JoinData, ManagerOptions, JoinOptions, LavalinkNodeOptions, ManagerEvents } from \"./Types\";\nimport { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdate, GatewayVoiceStateUpdateDispatchData } from \"discord-api-types/v10\";\n\n/**\n * Main class that handles Lavalink node connections and player management.\n *\n * @remarks\n * The Manager acts as the central hub for Lavacord, managing connections to Lavalink nodes,\n * handling voice state updates, and providing a unified interface for player operations.\n */\nexport class Manager extends EventEmitter<ManagerEvents> {\n\t/**\n\t * A Map of Lavalink Nodes indexed by their IDs.\n\t */\n\tpublic nodes = new Map<string, LavalinkNode>();\n\n\t/**\n\t * A Map of all active players indexed by guild ID.\n\t */\n\tpublic players = new Map<string, Player>();\n\n\t/**\n\t * A Map of voice server update states indexed by guild ID.\n\t */\n\tpublic voiceServers = new Map<string, GatewayVoiceServerUpdateDispatchData>();\n\n\t/**\n\t * A Map of voice state update states indexed by guild ID.\n\t */\n\tpublic voiceStates = new Map<string, GatewayVoiceStateUpdateDispatchData>();\n\n\t/**\n\t * The user ID of the bot this Manager is managing.\n\t */\n\tpublic userId: string | null = null;\n\n\t/**\n\t * Function to send voice state update packets to Discord.\n\t *\n\t * @remarks\n\t * This can be implemented by the user in two ways:\n\t * 1. Via constructor options: `new Manager(nodes, { send: fn })`\n\t * 2. Via class extension: `class MyManager extends Manager { send(packet) { ... } }`\n\t */\n\tprivate _send?: (packet: GatewayVoiceStateUpdate) => unknown;\n\n\t/**\n\t * The Player class constructor used when creating new players.\n\t *\n\t * @remarks\n\t * Can be overridden in the manager options to use a custom Player implementation.\n\t */\n\tprivate readonly Player: typeof Player = Player;\n\n\t/**\n\t * A Set of guild IDs that are waiting for a connection.\n\t *\n\t * @internal\n\t */\n\tprivate readonly expecting = new Set<string>();\n\n\t/**\n\t * Creates a new Manager instance.\n\t *\n\t * @param nodes - An array of Lavalink node options to connect to.\n\t * @param options - Configuration options for the Manager.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Method 1: Define send function via options\n\t * const manager = new Manager([\n\t * {\n\t * id: \"main\",\n\t * host: \"localhost\",\n\t * port: 2333,\n\t * password: \"youshallnotpass\"\n\t * }\n\t * ], {\n\t * userId: \"bot_user_id\",\n\t * send: (packet) => {\n\t * const guild = client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * });\n\t *\n\t * // Method 2: Extend Manager class\n\t * class MyManager extends Manager {\n\t * send(packet) {\n\t * const guild = this.client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * }\n\t * const manager = new MyManager(nodes, { userId: \"bot_user_id\" });\n\t * ```\n\t */\n\tpublic constructor(nodes: LavalinkNodeOptions[], options?: ManagerOptions) {\n\t\tsuper();\n\t\toptions ??= {};\n\n\t\tif (options.userId) this.userId = options.userId;\n\t\tif (options.player) this.Player = options.player;\n\t\tif (options.send && !this._send) this._send = options.send;\n\n\t\tfor (const node of nodes) this.createNode(node);\n\t}\n\n\t/**\n\t * Connects all Lavalink nodes to their respective Lavalink servers.\n\t *\n\t * @returns A promise that resolves when all connections are established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Connect all nodes\n\t * manager.connect()\n\t * .then(() => console.log('All nodes connected!'))\n\t * .catch(error => console.error('Failed to connect nodes:', error));\n\t * ```\n\t */\n\tpublic async connect(): Promise<LavalinkNode[]> {\n\t\tif (!this.userId)\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a client user ID before connecting. \\n\" +\n\t\t\t\t\t\"Set the user ID when constructing the Manager or after your Discord client is ready.\"\n\t\t\t);\n\t\treturn Promise.all(this.nodes.values().map((node) => node.connect().then(() => node)));\n\t}\n\n\t/**\n\t * Disconnects all players and nodes, effectively cleaning up all resources.\n\t *\n\t * @returns A promise that resolves when all disconnections are complete.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Disconnect everything\n\t * manager.disconnect()\n\t * .then(() => console.log('All players and nodes cleaned up'))\n\t * .catch(error => console.error('Error during disconnection:', error));\n\t * ```\n\t */\n\tpublic async disconnect(): Promise<void> {\n\t\tfor await (const player of this.players.keys()) await this.leave(player);\n\t\tfor (const node of this.nodes.values()) node.destroy();\n\t}\n\n\t/**\n\t * Creates a new Lavalink node and adds it to the nodes map.\n\t *\n\t * @param options - Configuration options for the node.\n\t * @returns The newly created LavalinkNode instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Add a new node\n\t * const newNode = manager.createNode({\n\t * id: \"node2\",\n\t * host: \"example.com\",\n\t * port: 2333,\n\t * password: \"securepassword\",\n\t * resuming: true\n\t * });\n\t * ```\n\t */\n\tpublic createNode(options: LavalinkNodeOptions): LavalinkNode {\n\t\tconst node = new LavalinkNode(this, options);\n\t\tthis.nodes.set(options.id, node);\n\t\treturn node;\n\t}\n\n\t/**\n\t * Disconnects and removes a node from the manager.\n\t *\n\t * @param id - The ID of the node to remove.\n\t * @returns Whether the node was successfully removed.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Remove a node\n\t * const removed = manager.removeNode(\"node1\");\n\t * if (removed) {\n\t * console.log(\"Node successfully removed\");\n\t * } else {\n\t * console.log(\"Node not found\");\n\t * }\n\t * ```\n\t */\n\tpublic removeNode(id: string): boolean {\n\t\tconst node = this.nodes.get(id);\n\t\tif (!node) return false;\n\t\tnode.destroy();\n\t\treturn this.nodes.delete(id);\n\t}\n\n\t/**\n\t * Joins a voice channel and creates a player for the guild.\n\t *\n\t * @param data - The data needed to join a voice channel.\n\t * @param joinOptions - Options for joining the channel (selfmute, selfdeaf).\n\t * @returns A promise resolving to the Player instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * const player = await manager.join({\n\t * guild: \"123456789012345678\", // Guild ID\n\t * channel: \"123456789012345679\", // Voice Channel ID\n\t * node: \"main\" // Node ID\n\t * }, {\n\t * selfdeaf: true // Join deafened\n\t * });\n\t *\n\t * // Now you can use the player to play music\n\t * const result = await Rest.load(player.node, \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n\t * await player.play(result.tracks[0].track);\n\t * ```\n\t */\n\tpublic async join(data: JoinData, joinOptions: JoinOptions = {}): Promise<Player> {\n\t\tconst player = this.players.get(data.guild);\n\t\tif (player) return player;\n\t\tawait this.sendWS(data.guild, data.channel, joinOptions);\n\t\treturn this.spawnPlayer(data);\n\t}\n\n\t/**\n\t * Leaves a voice channel and cleans up the player.\n\t *\n\t * @param guild - The ID of the guild to leave.\n\t * @returns A promise resolving to whether the operation was successful.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Leave a voice channel\n\t * const success = await manager.leave(\"123456789012345678\");\n\t * if (success) {\n\t * console.log(\"Successfully left the voice channel\");\n\t * } else {\n\t * console.log(\"Not in a voice channel in this guild\");\n\t * }\n\t * ```\n\t */\n\tpublic async leave(guild: string): Promise<boolean> {\n\t\tawait this.sendWS(guild, null);\n\t\tconst player = this.players.get(guild);\n\t\tif (!player) return false;\n\n\t\tawait player.destroy();\n\t\treturn this.players.delete(guild);\n\t}\n\n\t/**\n\t * Switches a player from one node to another, implementing fallback capability.\n\t *\n\t * @param player - The player to move to another node.\n\t * @param node - The destination node.\n\t * @returns A promise resolving to the updated player.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Switch a player to another node (e.g. if current node is failing)\n\t * const player = manager.players.get(\"123456789012345678\");\n\t * const newNode = manager.nodes.get(\"backup-node\");\n\t *\n\t * if (player && newNode) {\n\t * await manager.switch(player, newNode);\n\t * console.log(\"Player switched to backup node\");\n\t * }\n\t * ```\n\t */\n\tpublic async switch(player: Player, node: LavalinkNode): Promise<Player> {\n\t\tplayer.node = node;\n\n\t\tif (!player.voice) return player;\n\t\tawait player.destroy();\n\t\tif (!player.track) return player;\n\n\t\tawait player.play(player.track.encoded, {\n\t\t\tposition: player.state.position,\n\t\t\tvolume: player.volume,\n\t\t\tfilters: player.filters,\n\t\t\tvoice: player.voice,\n\t\t\tpaused: player.paused,\n\t\t\tuserData: player.track.userData\n\t\t});\n\n\t\treturn player;\n\t}\n\n\t/**\n\t * Processes voice server update events from Discord.\n\t *\n\t * @param data - The voice server update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => {\n\t * manager.voiceServerUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic voiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): Promise<boolean> {\n\t\tthis.voiceServers.set(data.guild_id, data);\n\t\tthis.expecting.add(data.guild_id);\n\t\treturn this._attemptConnection(data.guild_id);\n\t}\n\n\t/**\n\t * Processes voice state update events from Discord.\n\t *\n\t * @param data - The voice state update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => {\n\t * manager.voiceStateUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic async voiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): Promise<boolean> {\n\t\tif (data.user_id !== this.userId) return false;\n\t\tif (!data.guild_id) return false;\n\n\t\tif (data.channel_id) {\n\t\t\tthis.voiceStates.set(data.guild_id, data);\n\t\t\treturn this._attemptConnection(data.guild_id);\n\t\t}\n\n\t\tthis.voiceServers.delete(data.guild_id);\n\t\tthis.voiceStates.delete(data.guild_id);\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sends a voice state update packet to Discord.\n\t *\n\t * @param guild - The ID of the guild.\n\t * @param channel - The ID of the voice channel to join, or null to leave.\n\t * @param options - Options for joining (selfmute, selfdeaf).\n\t * @returns The result from the send function.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * manager.sendWS(\"123456789012345678\", \"123456789012345679\", { selfdeaf: true });\n\t *\n\t * // Leave a voice channel\n\t * manager.sendWS(\"123456789012345678\", null);\n\t * ```\n\t */\n\tpublic sendWS(guild: string, channel: string | null, { selfmute = false, selfdeaf = false }: JoinOptions = {}): unknown {\n\t\treturn this.send({\n\t\t\top: 4,\n\t\t\td: {\n\t\t\t\tguild_id: guild,\n\t\t\t\tchannel_id: channel,\n\t\t\t\tself_mute: selfmute,\n\t\t\t\tself_deaf: selfdeaf\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets all connected nodes, sorted by CPU load.\n\t *\n\t * @returns An array of connected nodes sorted by CPU load (least to most).\n\t *\n\t * @example\n\t * ```typescript\n\t * // Get the node with the least CPU load\n\t * const bestNode = manager.idealNodes[0];\n\t * if (bestNode) {\n\t * console.log(`Best node for new connections: ${bestNode.id}`);\n\t * }\n\t * ```\n\t */\n\tpublic get idealNodes(): LavalinkNode[] {\n\t\treturn Array.from(this.nodes.values())\n\t\t\t.filter((node) => node.connected)\n\t\t\t.sort((a, b) => {\n\t\t\t\tconst aload = a.stats.cpu ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100 : 0;\n\t\t\t\tconst bload = b.stats.cpu ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100 : 0;\n\t\t\t\treturn aload - bload;\n\t\t\t});\n\t}\n\n\t/**\n\t * Attempts to establish a connection for a guild using available voice data.\n\t *\n\t * @internal\n\t * @param guildID - The ID of the guild to attempt connecting.\n\t * @returns A promise resolving to whether a connection was established.\n\t */\n\tprivate async _attemptConnection(guildID: string): Promise<boolean> {\n\t\tconst server = this.voiceServers.get(guildID);\n\t\tconst state = this.voiceStates.get(guildID);\n\n\t\tif (!server || !state || !this.expecting.has(guildID)) return false;\n\n\t\tconst player = this.players.get(guildID);\n\t\tif (!player) return false;\n\n\t\tawait player.connect({ sessionId: state.session_id, event: server });\n\t\tthis.expecting.delete(guildID);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @internal\n\t * @param data - The data needed to create a player.\n\t * @returns The created Player instance.\n\t */\n\tprivate spawnPlayer(data: JoinData): Player {\n\t\tconst exists = this.players.get(data.guild);\n\t\tif (exists) return exists;\n\t\tconst node = this.nodes.get(data.node);\n\t\tif (!node) throw new Error(`INVALID_HOST: No available node with ${data.node}`);\n\t\tconst player = new this.Player(node, data.guild);\n\t\tthis.players.set(data.guild, player);\n\t\treturn player;\n\t}\n\n\tprotected send(packet: GatewayVoiceStateUpdate): unknown {\n\t\tif (typeof this._send !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a send function to be defined in the Manager options.\\\n\t\t\t\tThis function should send voice state updates to Discord.\"\n\t\t\t);\n\t\t}\n\t\treturn this._send(packet);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/Manager.ts"],"names":["EventEmitter","Player","LavalinkNode"],"mappings":"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","file":"Manager.cjs","sourcesContent":["import { EventEmitter } from \"events\";\nimport { LavalinkNode } from \"./LavalinkNode\";\nimport { Player } from \"./Player\";\nimport type { JoinData, ManagerOptions, JoinOptions, LavalinkNodeOptions, ManagerEvents } from \"./Types\";\nimport { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdate, GatewayVoiceStateUpdateDispatchData } from \"discord-api-types/v10\";\n\n/**\n * Main class that handles Lavalink node connections and player management.\n *\n * @remarks\n * The Manager acts as the central hub for Lavacord, managing connections to Lavalink nodes,\n * handling voice state updates, and providing a unified interface for player operations.\n */\nexport class Manager extends EventEmitter<ManagerEvents> {\n\t/**\n\t * A Map of Lavalink Nodes indexed by their IDs.\n\t */\n\tpublic nodes = new Map<string, LavalinkNode>();\n\n\t/**\n\t * A Map of all active players indexed by guild ID.\n\t */\n\tpublic players = new Map<string, Player>();\n\n\t/**\n\t * A Map of voice server update states indexed by guild ID.\n\t */\n\tpublic voiceServers = new Map<string, GatewayVoiceServerUpdateDispatchData>();\n\n\t/**\n\t * A Map of voice state update states indexed by guild ID.\n\t */\n\tpublic voiceStates = new Map<string, GatewayVoiceStateUpdateDispatchData>();\n\n\t/**\n\t * The user ID of the bot this Manager is managing.\n\t */\n\tpublic userId: string | null = null;\n\n\t/**\n\t * Function to send voice state update packets to Discord.\n\t *\n\t * @remarks\n\t * This can be implemented by the user in two ways:\n\t * 1. Via constructor options: `new Manager(nodes, { send: fn })`\n\t * 2. Via class extension: `class MyManager extends Manager { send(packet) { ... } }`\n\t */\n\tprivate _send?: (packet: GatewayVoiceStateUpdate) => unknown;\n\n\t/**\n\t * The Player class constructor used when creating new players.\n\t *\n\t * @remarks\n\t * Can be overridden in the manager options to use a custom Player implementation.\n\t */\n\tprivate readonly Player: typeof Player = Player;\n\n\t/**\n\t * A Set of guild IDs that are waiting for a connection.\n\t *\n\t * @internal\n\t */\n\tprivate readonly expecting = new Set<string>();\n\n\t/**\n\t * Creates a new Manager instance.\n\t *\n\t * @param nodes - An array of Lavalink node options to connect to.\n\t * @param options - Configuration options for the Manager.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Method 1: Define send function via options\n\t * const manager = new Manager([\n\t * {\n\t * id: \"main\",\n\t * host: \"localhost\",\n\t * port: 2333,\n\t * password: \"youshallnotpass\"\n\t * }\n\t * ], {\n\t * userId: \"bot_user_id\",\n\t * send: (packet) => {\n\t * const guild = client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * });\n\t *\n\t * // Method 2: Extend Manager class\n\t * class MyManager extends Manager {\n\t * send(packet) {\n\t * const guild = this.client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * }\n\t * const manager = new MyManager(nodes, { userId: \"bot_user_id\" });\n\t * ```\n\t */\n\tpublic constructor(nodes: LavalinkNodeOptions[], options?: ManagerOptions) {\n\t\tsuper();\n\t\toptions ??= {};\n\n\t\tif (options.userId) this.userId = options.userId;\n\t\tif (options.player) this.Player = options.player;\n\t\tif (options.send && !this._send) this._send = options.send;\n\n\t\tfor (const node of nodes) this.createNode(node);\n\t}\n\n\t/**\n\t * Connects all Lavalink nodes to their respective Lavalink servers.\n\t *\n\t * @returns A promise that resolves when all connections are established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Connect all nodes\n\t * manager.connect()\n\t * .then(() => console.log('All nodes connected!'))\n\t * .catch(error => console.error('Failed to connect nodes:', error));\n\t * ```\n\t */\n\tpublic async connect(): Promise<LavalinkNode[]> {\n\t\tif (!this.userId)\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a client user ID before connecting. \\n\" +\n\t\t\t\t\t\"Set the user ID when constructing the Manager or after your Discord client is ready.\"\n\t\t\t);\n\t\treturn Promise.all(this.nodes.values().map((node) => node.connect().then(() => node)));\n\t}\n\n\t/**\n\t * Disconnects all players and nodes, effectively cleaning up all resources.\n\t *\n\t * @returns A promise that resolves when all disconnections are complete.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Disconnect everything\n\t * manager.disconnect()\n\t * .then(() => console.log('All players and nodes cleaned up'))\n\t * .catch(error => console.error('Error during disconnection:', error));\n\t * ```\n\t */\n\tpublic async disconnect(): Promise<void> {\n\t\tfor await (const player of this.players.keys()) await this.leave(player);\n\t\tfor (const node of this.nodes.values()) node.destroy();\n\t}\n\n\t/**\n\t * Creates a new Lavalink node and adds it to the nodes map.\n\t *\n\t * @param options - Configuration options for the node.\n\t * @returns The newly created LavalinkNode instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Add a new node\n\t * const newNode = manager.createNode({\n\t * id: \"node2\",\n\t * host: \"example.com\",\n\t * port: 2333,\n\t * password: \"securepassword\",\n\t * resuming: true\n\t * });\n\t * ```\n\t */\n\tpublic createNode(options: LavalinkNodeOptions): LavalinkNode {\n\t\tconst node = new LavalinkNode(this, options);\n\t\tthis.nodes.set(options.id, node);\n\t\treturn node;\n\t}\n\n\t/**\n\t * Disconnects and removes a node from the manager.\n\t *\n\t * @param id - The ID of the node to remove.\n\t * @returns Whether the node was successfully removed.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Remove a node\n\t * const removed = manager.removeNode(\"node1\");\n\t * if (removed) {\n\t * console.log(\"Node successfully removed\");\n\t * } else {\n\t * console.log(\"Node not found\");\n\t * }\n\t * ```\n\t */\n\tpublic removeNode(id: string): boolean {\n\t\tconst node = this.nodes.get(id);\n\t\tif (!node) return false;\n\t\tnode.destroy();\n\t\treturn this.nodes.delete(id);\n\t}\n\n\t/**\n\t * Joins a voice channel and creates a player for the guild.\n\t *\n\t * @param data - The data needed to join a voice channel.\n\t * @param joinOptions - Options for joining the channel (selfmute, selfdeaf).\n\t * @returns A promise resolving to the Player instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * const player = await manager.join({\n\t * guild: \"123456789012345678\", // Guild ID\n\t * channel: \"123456789012345679\", // Voice Channel ID\n\t * node: \"main\" // Node ID\n\t * }, {\n\t * selfdeaf: true // Join deafened\n\t * });\n\t *\n\t * // Now you can use the player to play music\n\t * const result = await Rest.load(player.node, \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n\t * await player.play(result.tracks[0].track);\n\t * ```\n\t */\n\tpublic async join(data: JoinData, joinOptions: JoinOptions = {}): Promise<Player> {\n\t\tconst player = this.players.get(data.guild);\n\t\tif (player) return player;\n\t\tawait this.sendWS(data.guild, data.channel, joinOptions);\n\t\treturn this.spawnPlayer(data);\n\t}\n\n\t/**\n\t * Leaves a voice channel and cleans up the player.\n\t *\n\t * @param guild - The ID of the guild to leave.\n\t * @returns A promise resolving to whether the operation was successful.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Leave a voice channel\n\t * const success = await manager.leave(\"123456789012345678\");\n\t * if (success) {\n\t * console.log(\"Successfully left the voice channel\");\n\t * } else {\n\t * console.log(\"Not in a voice channel in this guild\");\n\t * }\n\t * ```\n\t */\n\tpublic async leave(guild: string): Promise<boolean> {\n\t\tawait this.sendWS(guild, null);\n\t\tconst player = this.players.get(guild);\n\t\tif (!player) return false;\n\n\t\tawait player.destroy();\n\t\treturn this.players.delete(guild);\n\t}\n\n\t/**\n\t * Switches a player from one node to another, implementing fallback capability.\n\t *\n\t * @param player - The player to move to another node.\n\t * @param node - The destination node.\n\t * @returns A promise resolving to the updated player.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Switch a player to another node (e.g. if current node is failing)\n\t * const player = manager.players.get(\"123456789012345678\");\n\t * const newNode = manager.nodes.get(\"backup-node\");\n\t *\n\t * if (player && newNode) {\n\t * await manager.switch(player, newNode);\n\t * console.log(\"Player switched to backup node\");\n\t * }\n\t * ```\n\t */\n\tpublic async switch(player: Player, node: LavalinkNode): Promise<Player> {\n\t\tplayer.node = node;\n\n\t\tif (!player.voice?.channelId) return player;\n\t\tawait player.destroy();\n\t\tif (!player.track) return player;\n\n\t\tawait player.play(player.track.encoded, {\n\t\t\tposition: player.state.position,\n\t\t\tvolume: player.volume,\n\t\t\tfilters: player.filters,\n\t\t\t// @ts-expect-error The type narrow for if no channelId didn't work\n\t\t\tvoice: player.voice,\n\t\t\tpaused: player.paused,\n\t\t\tuserData: player.track.userData\n\t\t});\n\n\t\treturn player;\n\t}\n\n\t/**\n\t * Processes voice server update events from Discord.\n\t *\n\t * @param data - The voice server update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => {\n\t * manager.voiceServerUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic voiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): Promise<boolean> {\n\t\tthis.voiceServers.set(data.guild_id, data);\n\t\tthis.expecting.add(data.guild_id);\n\t\treturn this._attemptConnection(data.guild_id);\n\t}\n\n\t/**\n\t * Processes voice state update events from Discord.\n\t *\n\t * @param data - The voice state update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => {\n\t * manager.voiceStateUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic async voiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): Promise<boolean> {\n\t\tif (data.user_id !== this.userId) return false;\n\t\tif (!data.guild_id) return false;\n\n\t\tif (data.channel_id) {\n\t\t\tthis.voiceStates.set(data.guild_id, data);\n\t\t\treturn this._attemptConnection(data.guild_id);\n\t\t}\n\n\t\tthis.voiceServers.delete(data.guild_id);\n\t\tthis.voiceStates.delete(data.guild_id);\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sends a voice state update packet to Discord.\n\t *\n\t * @param guild - The ID of the guild.\n\t * @param channel - The ID of the voice channel to join, or null to leave.\n\t * @param options - Options for joining (selfmute, selfdeaf).\n\t * @returns The result from the send function.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * manager.sendWS(\"123456789012345678\", \"123456789012345679\", { selfdeaf: true });\n\t *\n\t * // Leave a voice channel\n\t * manager.sendWS(\"123456789012345678\", null);\n\t * ```\n\t */\n\tpublic sendWS(guild: string, channel: string | null, { selfmute = false, selfdeaf = false }: JoinOptions = {}): unknown {\n\t\treturn this.send({\n\t\t\top: 4,\n\t\t\td: {\n\t\t\t\tguild_id: guild,\n\t\t\t\tchannel_id: channel,\n\t\t\t\tself_mute: selfmute,\n\t\t\t\tself_deaf: selfdeaf\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets all connected nodes, sorted by CPU load.\n\t *\n\t * @returns An array of connected nodes sorted by CPU load (least to most).\n\t *\n\t * @example\n\t * ```typescript\n\t * // Get the node with the least CPU load\n\t * const bestNode = manager.idealNodes[0];\n\t * if (bestNode) {\n\t * console.log(`Best node for new connections: ${bestNode.id}`);\n\t * }\n\t * ```\n\t */\n\tpublic get idealNodes(): LavalinkNode[] {\n\t\treturn Array.from(this.nodes.values())\n\t\t\t.filter((node) => node.connected)\n\t\t\t.sort((a, b) => {\n\t\t\t\tconst aload = a.stats.cpu ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100 : 0;\n\t\t\t\tconst bload = b.stats.cpu ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100 : 0;\n\t\t\t\treturn aload - bload;\n\t\t\t});\n\t}\n\n\t/**\n\t * Attempts to establish a connection for a guild using available voice data.\n\t *\n\t * @internal\n\t * @param guildID - The ID of the guild to attempt connecting.\n\t * @returns A promise resolving to whether a connection was established.\n\t */\n\tprivate async _attemptConnection(guildID: string): Promise<boolean> {\n\t\tconst server = this.voiceServers.get(guildID);\n\t\tconst state = this.voiceStates.get(guildID);\n\n\t\tif (!server || !state || !this.expecting.has(guildID)) return false;\n\n\t\tconst player = this.players.get(guildID);\n\t\tif (!player) return false;\n\n\t\tawait player.connect({ sessionId: state.session_id, event: server, channelId: state.channel_id! });\n\t\tthis.expecting.delete(guildID);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @internal\n\t * @param data - The data needed to create a player.\n\t * @returns The created Player instance.\n\t */\n\tprivate spawnPlayer(data: JoinData): Player {\n\t\tconst exists = this.players.get(data.guild);\n\t\tif (exists) return exists;\n\t\tconst node = this.nodes.get(data.node);\n\t\tif (!node) throw new Error(`INVALID_HOST: No available node with ${data.node}`);\n\t\tconst player = new this.Player(node, data.guild);\n\t\tthis.players.set(data.guild, player);\n\t\treturn player;\n\t}\n\n\tprotected send(packet: GatewayVoiceStateUpdate): unknown {\n\t\tif (typeof this._send !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a send function to be defined in the Manager options.\\\n\t\t\t\tThis function should send voice state updates to Discord.\"\n\t\t\t);\n\t\t}\n\t\treturn this._send(packet);\n\t}\n}\n"]}
|
package/dist/cjs/lib/Player.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/Player.ts"],"names":["EventEmitter","Rest"],"mappings":";;;;;;;AA0BO,IAAM,MAAA,GAAN,cAAqBA,mBAAA,CAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsD/C,WAAA,CAIC,MAIA,OAAA,EACN;AACD,IAAA,KAAA,EAAM;AANC,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAIA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA;AAGR,EA3FD;AA0BuD,IAAA,MAAA,CAAA,IAAA,EAAA,QAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/C,KAAA,GAAqB;AAAA,IAC3B,IAAA,EAAM,CAAA;AAAA,IACN,QAAA,EAAU,CAAA;AAAA,IACV,SAAA,EAAW,KAAA;AAAA,IACX,IAAA,EAAM;AAAA,GACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,SAAA,GAA2B,IAAA;AAAA;AAAA;AAAA;AAAA,EAI3B,MAAA,GAAS,KAAA;AAAA;AAAA;AAAA;AAAA,EAIT,MAAA,GAAS,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,KAAA,GAAsB,IAAA;AAAA;AAAA;AAAA;AAAA,EAItB,KAAA,GAA2B,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3B,UAAmB,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6B3B,MAAa,MAAA,CAAO,OAAA,EAA2B,SAAA,GAAY,KAAA,EAA2B;AACrF,IAAA,MAAM,CAAA,GAAI,MAAMC,aAAA,CAAK,YAAA,CAAa,KAAK,IAAA,EAAM,IAAA,CAAK,OAAA,EAAS,OAAA,EAAS,SAAS,CAAA;AAG7E,IAAA,IAAI,OAAA,IAAW,CAAA,EAAG,IAAA,CAAK,KAAA,GAAQ,CAAA,CAAE,KAAA;AACjC,IAAA,IAAI,QAAA,IAAY,CAAA,EAAG,IAAA,CAAK,MAAA,GAAS,CAAA,CAAE,MAAA;AACnC,IAAA,IAAI,QAAA,IAAY,CAAA,EAAG,IAAA,CAAK,MAAA,GAAS,CAAA,CAAE,MAAA;AACnC,IAAA,IAAI,OAAA,IAAW,CAAA,EAAG,IAAA,CAAK,KAAA,GAAQ,CAAA,CAAE,KAAA;AACjC,IAAA,IAAI,SAAA,IAAa,CAAA,EAAG,IAAA,CAAK,OAAA,GAAU,CAAA,CAAE,OAAA;AACrC,IAAA,IAAI,OAAA,IAAW,CAAA,EAAG,IAAA,CAAK,KAAA,GAAQ,CAAA,CAAE,KAAA;AAEjC,IAAA,OAAO,CAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,IAAA,CACZ,KAAA,EACA,OAAA,EAI8B;AAC9B,IAAA,MAAM,EAAE,QAAA,EAAU,SAAA,EAAW,GAAG,IAAA,EAAK,GAAI,WAAW,EAAC;AAErD,IAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,MAAA,CAAO,EAAE,KAAA,EAAO,EAAE,OAAA,EAAS,KAAA,EAAO,UAAS,EAAG,GAAG,IAAA,EAAK,EAAG,aAAa,KAAK,CAAA;AAChG,IAAA,IAAA,CAAK,SAAA,GAAY,KAAK,GAAA,EAAI;AAE1B,IAAA,OAAO,CAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,IAAA,GAAoC;AAC1C,IAAA,OAAO,IAAA,CAAK,OAAO,EAAE,KAAA,EAAO,EAAE,OAAA,EAAS,IAAA,IAAQ,CAAA;AAAA;AAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,MAAM,KAAA,EAA6C;AAC/D,IAAA,MAAM,IAAI,MAAM,IAAA,CAAK,OAAO,EAAE,MAAA,EAAQ,OAAO,CAAA;AAC7C,IAAA,IAAI,KAAK,aAAA,CAAc,OAAO,GAAG,IAAA,CAAK,IAAA,CAAK,SAAS,KAAK,CAAA;AACzD,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,aAAa,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,aAAA,EAAe,IAAA,EAAM,KAAK,CAAA;AAC3F,IAAA,OAAO,CAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,UAAU,MAAA,EAA6C;AACnE,IAAA,MAAM,IAAI,MAAM,IAAA,CAAK,MAAA,CAAO,EAAE,QAAQ,CAAA;AACtC,IAAA,IAAI,KAAK,aAAA,CAAc,QAAQ,GAAG,IAAA,CAAK,IAAA,CAAK,UAAU,MAAM,CAAA;AAC5D,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,cAAc,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,cAAA,EAAgB,IAAA,EAAM,MAAM,CAAA;AAC9F,IAAA,OAAO,CAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,KAAK,QAAA,EAA+C;AAChE,IAAA,MAAM,IAAI,MAAM,IAAA,CAAK,MAAA,CAAO,EAAE,UAAU,CAAA;AACxC,IAAA,IAAI,KAAK,aAAA,CAAc,MAAM,GAAG,IAAA,CAAK,IAAA,CAAK,QAAQ,QAAQ,CAAA;AAC1D,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,YAAY,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,YAAA,EAAc,IAAA,EAAM,QAAQ,CAAA;AAC5F,IAAA,OAAO,CAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,WAAW,OAAA,EAA+C;AACtE,IAAA,MAAM,IAAI,MAAM,IAAA,CAAK,OAAO,EAAE,OAAA,EAAS,SAAS,CAAA;AAChD,IAAA,IAAI,KAAK,aAAA,CAAc,SAAS,GAAG,IAAA,CAAK,IAAA,CAAK,WAAW,OAAO,CAAA;AAC/D,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,eAAe,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,eAAA,EAAiB,IAAA,EAAM,OAAO,CAAA;AACjG,IAAA,OAAO,CAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAa,aAAa,KAAA,EAAiD;AAC1E,IAAA,OAAO,IAAA,CAAK,UAAA,CAAW,EAAE,SAAA,EAAW,OAAO,CAAA;AAAA;AAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAa,OAAA,GAAwC;AACpD,IAAA,OAAOA,aAAA,CAAK,aAAA,CAAc,IAAA,CAAK,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA;AAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,QAAQ,IAAA,EAA2D;AACzE,IAAA,OAAO,KAAK,MAAA,CAAO;AAAA,MAClB,KAAA,EAAO;AAAA,QACN,KAAA,EAAO,KAAK,KAAA,CAAM,KAAA;AAAA,QAClB,QAAA,EAAU,KAAK,KAAA,CAAM,QAAA;AAAA,QACrB,WAAW,IAAA,CAAK;AAAA;AACjB,KACA,CAAA;AAAA;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,aAAA,CAAc,OAAA,EAAiB,OAAA,GAAuB,EAAC,EAAY;AACzE,IAAA,OAAO,KAAK,OAAA,CAAQ,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,SAAS,OAAO,CAAA;AAAA;AAC1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,OAAA,GAAmB;AAC7B,IAAA,OAAO,KAAK,IAAA,CAAK,OAAA;AAAA;AAEnB","file":"Player.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { EventEmitter } from \"events\";\nimport { Rest } from \"./Rest\";\nimport type { LavalinkNode } from \"./LavalinkNode\";\nimport type { Manager } from \"./Manager\";\nimport type { PlayerUpdateVoiceState, JoinOptions, PlayerEvents } from \"./Types\";\nimport {\n\tPlayerState,\n\tTrack,\n\tVoiceState,\n\tFilters,\n\tUpdatePlayerData,\n\tUpdatePlayerResult,\n\tEqualizer,\n\tDestroyPlayerResult,\n\tPlayer as APIPlayer\n} from \"lavalink-types\";\n\n/**\n * The Player class that handles playback and audio manipulation for a specific guild.\n *\n * @remarks\n * This class is responsible for audio playback operations, including playing, stopping,\n * pausing, resuming, and applying audio filters. Each instance represents a player\n * for a specific guild.\n */\nexport class Player extends EventEmitter<PlayerEvents> {\n\t/**\n\t * The current state of this Player\n\t *\n\t * @remarks\n\t * Contains information about the player state from Lavalink, including position, filters, etc.\n\t */\n\tpublic state: PlayerState = {\n\t\ttime: 0,\n\t\tposition: 0,\n\t\tconnected: false,\n\t\tping: 0\n\t};\n\t/**\n\t * The timestamp when the current track started playing\n\t *\n\t * @remarks\n\t * This is a client-side timestamp, not synchronized with Lavalink.\n\t * Can be used to calculate approximate playback position.\n\t */\n\tpublic timestamp: number | null = null;\n\t/**\n\t * Whether the audio playback is currently paused\n\t */\n\tpublic paused = false;\n\t/**\n\t * The current volume level (0-1000)\n\t */\n\tpublic volume = 100;\n\t/**\n\t * The current track in Lavalink's base64 string form\n\t *\n\t * @remarks\n\t * This is null when no track is loaded or when playback has ended.\n\t */\n\tpublic track: Track | null = null;\n\t/**\n\t * The voice connection state from Lavalink API\n\t */\n\tpublic voice: VoiceState | null = null;\n\t/**\n\t * The current audio filters applied to this player\n\t *\n\t * @remarks\n\t * This includes effects like equalizer, karaoke, etc.\n\t */\n\tpublic filters: Filters = {};\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @param node - The Lavalink node this player is connected to.\n\t * @param guildId - The guild ID that this player is associated with.\n\t */\n\tpublic constructor(\n\t\t/**\n\t\t * The Lavalink node this player is connected to\n\t\t */\n\t\tpublic node: LavalinkNode,\n\t\t/**\n\t\t * The guild ID for this player\n\t\t */\n\t\tpublic guildId: string\n\t) {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Updates the current player on the Lavalink node.\n\t * @see {@link https://lavalink.dev/api/rest#update-player}\n\t *\n\t * @param options - The update options to apply to the player.\n\t * @param noReplace - If true, the event will be dropped if there's a currently playing track.\n\t * @returns {Promise<APIPlayer>} The updated player information from Lavalink.\n\t */\n\tpublic async update(options: UpdatePlayerData, noReplace = false): Promise<APIPlayer> {\n\t\tconst d = await Rest.updatePlayer(this.node, this.guildId, options, noReplace);\n\n\t\t// Update local state with response data\n\t\tif (\"track\" in d) this.track = d.track;\n\t\tif (\"volume\" in d) this.volume = d.volume;\n\t\tif (\"paused\" in d) this.paused = d.paused;\n\t\tif (\"state\" in d) this.state = d.state;\n\t\tif (\"filters\" in d) this.filters = d.filters;\n\t\tif (\"voice\" in d) this.voice = d.voice;\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Plays a track using its base64 encoded string.\n\t *\n\t * @param track - The base64 encoded track string from Lavalink.\n\t * @param options - Additional options for playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async play(\n\t\ttrack: string,\n\t\toptions?: Omit<UpdatePlayerData, \"track\"> & {\n\t\t\tnoReplace?: boolean;\n\t\t\tuserData?: Record<any, any>;\n\t\t}\n\t): Promise<UpdatePlayerResult> {\n\t\tconst { userData, noReplace, ...opts } = options || {};\n\n\t\tconst d = await this.update({ track: { encoded: track, userData }, ...opts }, noReplace ?? false);\n\t\tthis.timestamp = Date.now();\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Stops the currently playing track.\n\t *\n\t * @remarks\n\t * This will trigger a \"TrackEndEvent\" with reason \"STOPPED\".\n\t *\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic stop(): Promise<UpdatePlayerResult> {\n\t\treturn this.update({ track: { encoded: null } });\n\t}\n\n\t/**\n\t * Pauses or resumes the current track.\n\t *\n\t * @param pause - Whether to pause (true) or resume (false) playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async pause(pause: boolean): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ paused: pause });\n\t\tif (this.listenerCount(\"pause\")) this.emit(\"pause\", pause);\n\t\tif (this.manager.listenerCount(\"playerPause\")) this.manager.emit(\"playerPause\", this, pause);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Changes the volume of the current playback.\n\t *\n\t * @param volume - The volume level as a number between 0 and 1000\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setVolume(volume: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ volume });\n\t\tif (this.listenerCount(\"volume\")) this.emit(\"volume\", volume);\n\t\tif (this.manager.listenerCount(\"playerVolume\")) this.manager.emit(\"playerVolume\", this, volume);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Seeks to a specific position in the current track.\n\t *\n\t * @param position - The position to seek to in milliseconds.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async seek(position: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ position });\n\t\tif (this.listenerCount(\"seek\")) this.emit(\"seek\", position);\n\t\tif (this.manager.listenerCount(\"playerSeek\")) this.manager.emit(\"playerSeek\", this, position);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Applies audio filters to the current playback.\n\t *\n\t * @param options - The filter options to apply.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setFilters(options: Filters): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ filters: options });\n\t\tif (this.listenerCount(\"filters\")) this.emit(\"filters\", options);\n\t\tif (this.manager.listenerCount(\"playerFilters\")) this.manager.emit(\"playerFilters\", this, options);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Sets the equalizer effect for the current playback.\n\t *\n\t * @param bands - An array of equalizer bands to adjust.\n\t * @returns A promise resolving to the updated player information.\n\t *\n\t * @remarks\n\t * Each band is an object with 'band' (0-14) and 'gain' (-0.25 to 1.0) properties.\n\t */\n\tpublic async setEqualizer(bands: Equalizer[]): Promise<UpdatePlayerResult> {\n\t\treturn this.setFilters({ equalizer: bands });\n\t}\n\n\t/**\n\t * Destroys the player on the Lavalink node.\n\t *\n\t * @remarks\n\t * This sends a destroy signal to Lavalink to clean up resources for this guild ID.\n\t * It doesn't affect the Discord voice connection - use {@link Manager.leave} for that.\n\t *\n\t * @returns {Promise<DestroyPlayerResult>} A promise resolving to the destroy result.\n\t */\n\tpublic async destroy(): Promise<DestroyPlayerResult> {\n\t\treturn Rest.destroyPlayer(this.node, this.guildId);\n\t}\n\n\t/**\n\t * Provides voice server update information to Lavalink to establish a connection.\n\t *\n\t * @param data - The voice update state containing session ID and voice server information.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic connect(data: PlayerUpdateVoiceState): Promise<UpdatePlayerResult> {\n\t\treturn this.update({\n\t\t\tvoice: {\n\t\t\t\ttoken: data.event.token,\n\t\t\t\tendpoint: data.event.endpoint,\n\t\t\t\tsessionId: data.sessionId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Switches the player to a different voice channel.\n\t *\n\t * @param channel - The ID of the voice channel to switch to.\n\t * @param options - Options for joining the channel (selfMute, selfDeaf).\n\t * @returns Does not return anything, but sends a WebSocket message to the Lavalink node.\n\t */\n\tpublic switchChannel(channel: string, options: JoinOptions = {}): unknown {\n\t\treturn this.manager.sendWS(this.guildId, channel, options);\n\t}\n\n\t/**\n\t * Gets the manager instance that created this player.\n\t *\n\t * @returns {Manager} The manager instance.\n\t */\n\tpublic get manager(): Manager {\n\t\treturn this.node.manager;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/Player.ts"],"names":["EventEmitter","Rest"],"mappings":"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","file":"Player.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { EventEmitter } from \"events\";\nimport { Rest } from \"./Rest\";\nimport type { LavalinkNode } from \"./LavalinkNode\";\nimport type { Manager } from \"./Manager\";\nimport type { PlayerUpdateVoiceState, JoinOptions, PlayerEvents } from \"./Types\";\nimport {\n\tPlayerState,\n\tTrack,\n\tVoiceState,\n\tFilters,\n\tUpdatePlayerData,\n\tUpdatePlayerResult,\n\tEqualizer,\n\tDestroyPlayerResult,\n\tPlayer as APIPlayer\n} from \"lavalink-types\";\n\n/**\n * The Player class that handles playback and audio manipulation for a specific guild.\n *\n * @remarks\n * This class is responsible for audio playback operations, including playing, stopping,\n * pausing, resuming, and applying audio filters. Each instance represents a player\n * for a specific guild.\n */\nexport class Player extends EventEmitter<PlayerEvents> {\n\t/**\n\t * The current state of this Player\n\t *\n\t * @remarks\n\t * Contains information about the player state from Lavalink, including position, filters, etc.\n\t */\n\tpublic state: PlayerState = {\n\t\ttime: 0,\n\t\tposition: 0,\n\t\tconnected: false,\n\t\tping: 0\n\t};\n\t/**\n\t * The timestamp when the current track started playing\n\t *\n\t * @remarks\n\t * This is a client-side timestamp, not synchronized with Lavalink.\n\t * Can be used to calculate approximate playback position.\n\t */\n\tpublic timestamp: number | null = null;\n\t/**\n\t * Whether the audio playback is currently paused\n\t */\n\tpublic paused = false;\n\t/**\n\t * The current volume level (0-1000)\n\t */\n\tpublic volume = 100;\n\t/**\n\t * The current track in Lavalink's base64 string form\n\t *\n\t * @remarks\n\t * This is null when no track is loaded or when playback has ended.\n\t */\n\tpublic track: Track | null = null;\n\t/**\n\t * The voice connection state from Lavalink API\n\t */\n\tpublic voice: VoiceState | null = null;\n\t/**\n\t * The current audio filters applied to this player\n\t *\n\t * @remarks\n\t * This includes effects like equalizer, karaoke, etc.\n\t */\n\tpublic filters: Filters = {};\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @param node - The Lavalink node this player is connected to.\n\t * @param guildId - The guild ID that this player is associated with.\n\t */\n\tpublic constructor(\n\t\t/**\n\t\t * The Lavalink node this player is connected to\n\t\t */\n\t\tpublic node: LavalinkNode,\n\t\t/**\n\t\t * The guild ID for this player\n\t\t */\n\t\tpublic guildId: string\n\t) {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Updates the current player on the Lavalink node.\n\t * @see {@link https://lavalink.dev/api/rest#update-player}\n\t *\n\t * @param options - The update options to apply to the player.\n\t * @param noReplace - If true, the event will be dropped if there's a currently playing track.\n\t * @returns {Promise<APIPlayer>} The updated player information from Lavalink.\n\t */\n\tpublic async update(options: UpdatePlayerData, noReplace = false): Promise<APIPlayer> {\n\t\tconst d = await Rest.updatePlayer(this.node, this.guildId, options, noReplace);\n\n\t\t// Update local state with response data\n\t\tif (\"track\" in d) this.track = d.track;\n\t\tif (\"volume\" in d) this.volume = d.volume;\n\t\tif (\"paused\" in d) this.paused = d.paused;\n\t\tif (\"state\" in d) this.state = d.state;\n\t\tif (\"filters\" in d) this.filters = d.filters;\n\t\tif (\"voice\" in d) this.voice = d.voice;\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Plays a track using its base64 encoded string.\n\t *\n\t * @param track - The base64 encoded track string from Lavalink.\n\t * @param options - Additional options for playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async play(\n\t\ttrack: string,\n\t\toptions?: Omit<UpdatePlayerData, \"track\"> & {\n\t\t\tnoReplace?: boolean;\n\t\t\tuserData?: Record<any, any>;\n\t\t}\n\t): Promise<UpdatePlayerResult> {\n\t\tconst { userData, noReplace, ...opts } = options || {};\n\n\t\tconst d = await this.update({ track: { encoded: track, userData }, ...opts }, noReplace ?? false);\n\t\tthis.timestamp = Date.now();\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Stops the currently playing track.\n\t *\n\t * @remarks\n\t * This will trigger a \"TrackEndEvent\" with reason \"STOPPED\".\n\t *\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic stop(): Promise<UpdatePlayerResult> {\n\t\treturn this.update({ track: { encoded: null } });\n\t}\n\n\t/**\n\t * Pauses or resumes the current track.\n\t *\n\t * @param pause - Whether to pause (true) or resume (false) playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async pause(pause: boolean): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ paused: pause });\n\t\tif (this.listenerCount(\"pause\")) this.emit(\"pause\", pause);\n\t\tif (this.manager.listenerCount(\"playerPause\")) this.manager.emit(\"playerPause\", this, pause);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Changes the volume of the current playback.\n\t *\n\t * @param volume - The volume level as a number between 0 and 1000\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setVolume(volume: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ volume });\n\t\tif (this.listenerCount(\"volume\")) this.emit(\"volume\", volume);\n\t\tif (this.manager.listenerCount(\"playerVolume\")) this.manager.emit(\"playerVolume\", this, volume);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Seeks to a specific position in the current track.\n\t *\n\t * @param position - The position to seek to in milliseconds.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async seek(position: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ position });\n\t\tif (this.listenerCount(\"seek\")) this.emit(\"seek\", position);\n\t\tif (this.manager.listenerCount(\"playerSeek\")) this.manager.emit(\"playerSeek\", this, position);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Applies audio filters to the current playback.\n\t *\n\t * @param options - The filter options to apply.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setFilters(options: Filters): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ filters: options });\n\t\tif (this.listenerCount(\"filters\")) this.emit(\"filters\", options);\n\t\tif (this.manager.listenerCount(\"playerFilters\")) this.manager.emit(\"playerFilters\", this, options);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Sets the equalizer effect for the current playback.\n\t *\n\t * @param bands - An array of equalizer bands to adjust.\n\t * @returns A promise resolving to the updated player information.\n\t *\n\t * @remarks\n\t * Each band is an object with 'band' (0-14) and 'gain' (-0.25 to 1.0) properties.\n\t */\n\tpublic async setEqualizer(bands: Equalizer[]): Promise<UpdatePlayerResult> {\n\t\treturn this.setFilters({ equalizer: bands });\n\t}\n\n\t/**\n\t * Destroys the player on the Lavalink node.\n\t *\n\t * @remarks\n\t * This sends a destroy signal to Lavalink to clean up resources for this guild ID.\n\t * It doesn't affect the Discord voice connection - use {@link Manager.leave} for that.\n\t *\n\t * @returns {Promise<DestroyPlayerResult>} A promise resolving to the destroy result.\n\t */\n\tpublic async destroy(): Promise<DestroyPlayerResult> {\n\t\treturn Rest.destroyPlayer(this.node, this.guildId);\n\t}\n\n\t/**\n\t * Provides voice server update information to Lavalink to establish a connection.\n\t *\n\t * @param data - The voice update state containing session ID and voice server information.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic connect(data: PlayerUpdateVoiceState): Promise<UpdatePlayerResult> {\n\t\treturn this.update({\n\t\t\tvoice: {\n\t\t\t\ttoken: data.event.token,\n\t\t\t\tendpoint: data.event.endpoint,\n\t\t\t\tsessionId: data.sessionId,\n\t\t\t\tchannelId: data.channelId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Switches the player to a different voice channel.\n\t *\n\t * @param channel - The ID of the voice channel to switch to.\n\t * @param options - Options for joining the channel (selfMute, selfDeaf).\n\t * @returns Does not return anything, but sends a WebSocket message to the Lavalink node.\n\t */\n\tpublic switchChannel(channel: string, options: JoinOptions = {}): unknown {\n\t\treturn this.manager.sendWS(this.guildId, channel, options);\n\t}\n\n\t/**\n\t * Gets the manager instance that created this player.\n\t *\n\t * @returns {Manager} The manager instance.\n\t */\n\tpublic get manager(): Manager {\n\t\treturn this.node.manager;\n\t}\n}\n"]}
|
package/dist/esm/index.d.mts
CHANGED
|
@@ -27,6 +27,12 @@ interface PlayerUpdateVoiceState {
|
|
|
27
27
|
* @readonly
|
|
28
28
|
*/
|
|
29
29
|
event: GatewayVoiceServerUpdateDispatchData;
|
|
30
|
+
/**
|
|
31
|
+
* The ID of the voice channel.
|
|
32
|
+
*
|
|
33
|
+
* @readonly
|
|
34
|
+
*/
|
|
35
|
+
channelId: string;
|
|
30
36
|
}
|
|
31
37
|
/**
|
|
32
38
|
* Defines the options for configuring the Lavacord Manager.
|
package/dist/esm/index.mjs
CHANGED
package/dist/esm/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;AAYO,IAAM,OAAA,GAAkB","file":"index.mjs","sourcesContent":["/**\n * @module Lavacord\n */\nexport * from \"./lib/LavalinkNode\";\nexport * from \"./lib/Player\";\nexport * from \"./lib/Manager\";\nexport * from \"./lib/Rest\";\nexport * from \"./lib/Types\";\n\n// This is a placeholder for the version of the library, which should be injected during build time\n// this need to be explicitly typed as string.\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const VERSION: string = \"3.0
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;AAYO,IAAM,OAAA,GAAkB","file":"index.mjs","sourcesContent":["/**\n * @module Lavacord\n */\nexport * from \"./lib/LavalinkNode\";\nexport * from \"./lib/Player\";\nexport * from \"./lib/Manager\";\nexport * from \"./lib/Rest\";\nexport * from \"./lib/Types\";\n\n// This is a placeholder for the version of the library, which should be injected during build time\n// this need to be explicitly typed as string.\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const VERSION: string = \"3.1.0\";\n"]}
|
package/dist/esm/lib/Manager.mjs
CHANGED
|
@@ -248,13 +248,14 @@ var Manager = class extends EventEmitter {
|
|
|
248
248
|
*/
|
|
249
249
|
async switch(player, node) {
|
|
250
250
|
player.node = node;
|
|
251
|
-
if (!player.voice) return player;
|
|
251
|
+
if (!player.voice?.channelId) return player;
|
|
252
252
|
await player.destroy();
|
|
253
253
|
if (!player.track) return player;
|
|
254
254
|
await player.play(player.track.encoded, {
|
|
255
255
|
position: player.state.position,
|
|
256
256
|
volume: player.volume,
|
|
257
257
|
filters: player.filters,
|
|
258
|
+
// @ts-expect-error The type narrow for if no channelId didn't work
|
|
258
259
|
voice: player.voice,
|
|
259
260
|
paused: player.paused,
|
|
260
261
|
userData: player.track.userData
|
|
@@ -367,7 +368,7 @@ var Manager = class extends EventEmitter {
|
|
|
367
368
|
if (!server || !state || !this.expecting.has(guildID)) return false;
|
|
368
369
|
const player = this.players.get(guildID);
|
|
369
370
|
if (!player) return false;
|
|
370
|
-
await player.connect({ sessionId: state.session_id, event: server });
|
|
371
|
+
await player.connect({ sessionId: state.session_id, event: server, channelId: state.channel_id });
|
|
371
372
|
this.expecting.delete(guildID);
|
|
372
373
|
return true;
|
|
373
374
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/Manager.ts"],"names":[],"mappings":";;;;;AAaO,IAAM,OAAA,GAAN,cAAsB,YAAA,CAA4B;AAAA,EAbzD;AAayD,IAAA,MAAA,CAAA,IAAA,EAAA,SAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIjD,KAAA,uBAAY,GAAA,EAA0B;AAAA;AAAA;AAAA;AAAA,EAKtC,OAAA,uBAAc,GAAA,EAAoB;AAAA;AAAA;AAAA;AAAA,EAKlC,YAAA,uBAAmB,GAAA,EAAkD;AAAA;AAAA;AAAA;AAAA,EAKrE,WAAA,uBAAkB,GAAA,EAAiD;AAAA;AAAA;AAAA;AAAA,EAKnE,MAAA,GAAwB,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUvB,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQS,MAAA,GAAwB,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOxB,SAAA,uBAAgB,GAAA,EAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoCtC,WAAA,CAAY,OAA8B,OAAA,EAA0B;AAC1E,IAAA,KAAA,EAAM;AACN,IAAA,OAAA,KAAY,EAAC;AAEb,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,GAAS,OAAA,CAAQ,MAAA;AAC1C,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,GAAS,OAAA,CAAQ,MAAA;AAC1C,IAAA,IAAI,QAAQ,IAAA,IAAQ,CAAC,KAAK,KAAA,EAAO,IAAA,CAAK,QAAQ,OAAA,CAAQ,IAAA;AAEtD,IAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AAAA;AAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAa,OAAA,GAAmC;AAC/C,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA;AACT,MAAA,MAAM,IAAI,KAAA;AAAA,QACT;AAAA,OAED;AACD,IAAA,OAAO,QAAQ,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,SAAQ,CAAE,IAAA,CAAK,MAAM,IAAI,CAAC,CAAC,CAAA;AAAA;AACtF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAa,UAAA,GAA4B;AACxC,IAAA,WAAA,MAAiB,MAAA,IAAU,KAAK,OAAA,CAAQ,IAAA,IAAQ,MAAM,IAAA,CAAK,MAAM,MAAM,CAAA;AACvE,IAAA,KAAA,MAAW,QAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,EAAO,OAAQ,OAAA,EAAQ;AAAA;AACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBO,WAAW,OAAA,EAA4C;AAC7D,IAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,IAAA,EAAM,OAAO,CAAA;AAC3C,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,OAAA,CAAQ,EAAA,EAAI,IAAI,CAAA;AAC/B,IAAA,OAAO,IAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBO,WAAW,EAAA,EAAqB;AACtC,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,IAAA,IAAA,CAAK,OAAA,EAAQ;AACb,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,EAAE,CAAA;AAAA;AAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBA,MAAa,IAAA,CAAK,IAAA,EAAgB,WAAA,GAA2B,EAAC,EAAoB;AACjF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,KAAK,CAAA;AAC1C,IAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,IAAA,MAAM,KAAK,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,SAAS,WAAW,CAAA;AACvD,IAAA,OAAO,IAAA,CAAK,YAAY,IAAI,CAAA;AAAA;AAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAa,MAAM,KAAA,EAAiC;AACnD,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,KAAA,EAAO,IAAI,CAAA;AAC7B,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AACrC,IAAA,IAAI,CAAC,QAAQ,OAAO,KAAA;AAEpB,IAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAA;AAAA;AACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAAa,MAAA,CAAO,MAAA,EAAgB,IAAA,EAAqC;AACxE,IAAA,MAAA,CAAO,IAAA,GAAO,IAAA;AAEd,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,EAAO,OAAO,MAAA;AAC1B,IAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,EAAO,OAAO,MAAA;AAE1B,IAAA,MAAM,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS;AAAA,MACvC,QAAA,EAAU,OAAO,KAAA,CAAM,QAAA;AAAA,MACvB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,QAAA,EAAU,OAAO,KAAA,CAAM;AAAA,KACvB,CAAA;AAED,IAAA,OAAO,MAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBO,kBAAkB,IAAA,EAA8D;AACtF,IAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AACzC,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA;AAChC,IAAA,OAAO,IAAA,CAAK,kBAAA,CAAmB,IAAA,CAAK,QAAQ,CAAA;AAAA;AAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAa,iBAAiB,IAAA,EAA6D;AAC1F,IAAA,IAAI,IAAA,CAAK,OAAA,KAAY,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAA;AACzC,IAAA,IAAI,CAAC,IAAA,CAAK,QAAA,EAAU,OAAO,KAAA;AAE3B,IAAA,IAAI,KAAK,UAAA,EAAY;AACpB,MAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AACxC,MAAA,OAAO,IAAA,CAAK,kBAAA,CAAmB,IAAA,CAAK,QAAQ,CAAA;AAAA;AAG7C,IAAA,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA;AACtC,IAAA,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA;AAErC,IAAA,OAAO,KAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBO,MAAA,CAAO,KAAA,EAAe,OAAA,EAAwB,EAAE,QAAA,GAAW,OAAO,QAAA,GAAW,KAAA,EAAM,GAAiB,EAAC,EAAY;AACvH,IAAA,OAAO,KAAK,IAAA,CAAK;AAAA,MAChB,EAAA,EAAI,CAAA;AAAA,MACJ,CAAA,EAAG;AAAA,QACF,QAAA,EAAU,KAAA;AAAA,QACV,UAAA,EAAY,OAAA;AAAA,QACZ,SAAA,EAAW,QAAA;AAAA,QACX,SAAA,EAAW;AAAA;AACZ,KACA,CAAA;AAAA;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,IAAW,UAAA,GAA6B;AACvC,IAAA,OAAO,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,CAAA,CACnC,MAAA,CAAO,CAAC,IAAA,KAAS,KAAK,SAAS,CAAA,CAC/B,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AACf,MAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,KAAA,CAAM,GAAA,GAAO,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,UAAA,GAAa,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,KAAA,GAAS,GAAA,GAAM,CAAA;AACjF,MAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,KAAA,CAAM,GAAA,GAAO,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,UAAA,GAAa,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,KAAA,GAAS,GAAA,GAAM,CAAA;AACjF,MAAA,OAAO,KAAA,GAAQ,KAAA;AAAA,KACf,CAAA;AAAA;AACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,mBAAmB,OAAA,EAAmC;AACnE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AAC5C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,OAAO,CAAA;AAE1C,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,KAAA,IAAS,CAAC,KAAK,SAAA,CAAU,GAAA,CAAI,OAAO,CAAA,EAAG,OAAO,KAAA;AAE9D,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA;AACvC,IAAA,IAAI,CAAC,QAAQ,OAAO,KAAA;AAEpB,IAAA,MAAM,MAAA,CAAO,QAAQ,EAAE,SAAA,EAAW,MAAM,UAAA,EAAY,KAAA,EAAO,QAAQ,CAAA;AACnE,IAAA,IAAA,CAAK,SAAA,CAAU,OAAO,OAAO,CAAA;AAE7B,IAAA,OAAO,IAAA;AAAA;AACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,YAAY,IAAA,EAAwB;AAC3C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,KAAK,CAAA;AAC1C,IAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,KAAK,IAAI,CAAA;AACrC,IAAA,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,CAAA,qCAAA,EAAwC,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AAC9E,IAAA,MAAM,SAAS,IAAI,IAAA,CAAK,MAAA,CAAO,IAAA,EAAM,KAAK,KAAK,CAAA;AAC/C,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,KAAA,EAAO,MAAM,CAAA;AACnC,IAAA,OAAO,MAAA;AAAA;AACR,EAEU,KAAK,MAAA,EAA0C;AACxD,IAAA,IAAI,OAAO,IAAA,CAAK,KAAA,KAAU,UAAA,EAAY;AACrC,MAAA,MAAM,IAAI,KAAA;AAAA,QACT;AAAA,OAED;AAAA;AAED,IAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA;AAE1B","file":"Manager.mjs","sourcesContent":["import { EventEmitter } from \"events\";\nimport { LavalinkNode } from \"./LavalinkNode\";\nimport { Player } from \"./Player\";\nimport type { JoinData, ManagerOptions, JoinOptions, LavalinkNodeOptions, ManagerEvents } from \"./Types\";\nimport { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdate, GatewayVoiceStateUpdateDispatchData } from \"discord-api-types/v10\";\n\n/**\n * Main class that handles Lavalink node connections and player management.\n *\n * @remarks\n * The Manager acts as the central hub for Lavacord, managing connections to Lavalink nodes,\n * handling voice state updates, and providing a unified interface for player operations.\n */\nexport class Manager extends EventEmitter<ManagerEvents> {\n\t/**\n\t * A Map of Lavalink Nodes indexed by their IDs.\n\t */\n\tpublic nodes = new Map<string, LavalinkNode>();\n\n\t/**\n\t * A Map of all active players indexed by guild ID.\n\t */\n\tpublic players = new Map<string, Player>();\n\n\t/**\n\t * A Map of voice server update states indexed by guild ID.\n\t */\n\tpublic voiceServers = new Map<string, GatewayVoiceServerUpdateDispatchData>();\n\n\t/**\n\t * A Map of voice state update states indexed by guild ID.\n\t */\n\tpublic voiceStates = new Map<string, GatewayVoiceStateUpdateDispatchData>();\n\n\t/**\n\t * The user ID of the bot this Manager is managing.\n\t */\n\tpublic userId: string | null = null;\n\n\t/**\n\t * Function to send voice state update packets to Discord.\n\t *\n\t * @remarks\n\t * This can be implemented by the user in two ways:\n\t * 1. Via constructor options: `new Manager(nodes, { send: fn })`\n\t * 2. Via class extension: `class MyManager extends Manager { send(packet) { ... } }`\n\t */\n\tprivate _send?: (packet: GatewayVoiceStateUpdate) => unknown;\n\n\t/**\n\t * The Player class constructor used when creating new players.\n\t *\n\t * @remarks\n\t * Can be overridden in the manager options to use a custom Player implementation.\n\t */\n\tprivate readonly Player: typeof Player = Player;\n\n\t/**\n\t * A Set of guild IDs that are waiting for a connection.\n\t *\n\t * @internal\n\t */\n\tprivate readonly expecting = new Set<string>();\n\n\t/**\n\t * Creates a new Manager instance.\n\t *\n\t * @param nodes - An array of Lavalink node options to connect to.\n\t * @param options - Configuration options for the Manager.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Method 1: Define send function via options\n\t * const manager = new Manager([\n\t * {\n\t * id: \"main\",\n\t * host: \"localhost\",\n\t * port: 2333,\n\t * password: \"youshallnotpass\"\n\t * }\n\t * ], {\n\t * userId: \"bot_user_id\",\n\t * send: (packet) => {\n\t * const guild = client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * });\n\t *\n\t * // Method 2: Extend Manager class\n\t * class MyManager extends Manager {\n\t * send(packet) {\n\t * const guild = this.client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * }\n\t * const manager = new MyManager(nodes, { userId: \"bot_user_id\" });\n\t * ```\n\t */\n\tpublic constructor(nodes: LavalinkNodeOptions[], options?: ManagerOptions) {\n\t\tsuper();\n\t\toptions ??= {};\n\n\t\tif (options.userId) this.userId = options.userId;\n\t\tif (options.player) this.Player = options.player;\n\t\tif (options.send && !this._send) this._send = options.send;\n\n\t\tfor (const node of nodes) this.createNode(node);\n\t}\n\n\t/**\n\t * Connects all Lavalink nodes to their respective Lavalink servers.\n\t *\n\t * @returns A promise that resolves when all connections are established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Connect all nodes\n\t * manager.connect()\n\t * .then(() => console.log('All nodes connected!'))\n\t * .catch(error => console.error('Failed to connect nodes:', error));\n\t * ```\n\t */\n\tpublic async connect(): Promise<LavalinkNode[]> {\n\t\tif (!this.userId)\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a client user ID before connecting. \\n\" +\n\t\t\t\t\t\"Set the user ID when constructing the Manager or after your Discord client is ready.\"\n\t\t\t);\n\t\treturn Promise.all(this.nodes.values().map((node) => node.connect().then(() => node)));\n\t}\n\n\t/**\n\t * Disconnects all players and nodes, effectively cleaning up all resources.\n\t *\n\t * @returns A promise that resolves when all disconnections are complete.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Disconnect everything\n\t * manager.disconnect()\n\t * .then(() => console.log('All players and nodes cleaned up'))\n\t * .catch(error => console.error('Error during disconnection:', error));\n\t * ```\n\t */\n\tpublic async disconnect(): Promise<void> {\n\t\tfor await (const player of this.players.keys()) await this.leave(player);\n\t\tfor (const node of this.nodes.values()) node.destroy();\n\t}\n\n\t/**\n\t * Creates a new Lavalink node and adds it to the nodes map.\n\t *\n\t * @param options - Configuration options for the node.\n\t * @returns The newly created LavalinkNode instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Add a new node\n\t * const newNode = manager.createNode({\n\t * id: \"node2\",\n\t * host: \"example.com\",\n\t * port: 2333,\n\t * password: \"securepassword\",\n\t * resuming: true\n\t * });\n\t * ```\n\t */\n\tpublic createNode(options: LavalinkNodeOptions): LavalinkNode {\n\t\tconst node = new LavalinkNode(this, options);\n\t\tthis.nodes.set(options.id, node);\n\t\treturn node;\n\t}\n\n\t/**\n\t * Disconnects and removes a node from the manager.\n\t *\n\t * @param id - The ID of the node to remove.\n\t * @returns Whether the node was successfully removed.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Remove a node\n\t * const removed = manager.removeNode(\"node1\");\n\t * if (removed) {\n\t * console.log(\"Node successfully removed\");\n\t * } else {\n\t * console.log(\"Node not found\");\n\t * }\n\t * ```\n\t */\n\tpublic removeNode(id: string): boolean {\n\t\tconst node = this.nodes.get(id);\n\t\tif (!node) return false;\n\t\tnode.destroy();\n\t\treturn this.nodes.delete(id);\n\t}\n\n\t/**\n\t * Joins a voice channel and creates a player for the guild.\n\t *\n\t * @param data - The data needed to join a voice channel.\n\t * @param joinOptions - Options for joining the channel (selfmute, selfdeaf).\n\t * @returns A promise resolving to the Player instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * const player = await manager.join({\n\t * guild: \"123456789012345678\", // Guild ID\n\t * channel: \"123456789012345679\", // Voice Channel ID\n\t * node: \"main\" // Node ID\n\t * }, {\n\t * selfdeaf: true // Join deafened\n\t * });\n\t *\n\t * // Now you can use the player to play music\n\t * const result = await Rest.load(player.node, \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n\t * await player.play(result.tracks[0].track);\n\t * ```\n\t */\n\tpublic async join(data: JoinData, joinOptions: JoinOptions = {}): Promise<Player> {\n\t\tconst player = this.players.get(data.guild);\n\t\tif (player) return player;\n\t\tawait this.sendWS(data.guild, data.channel, joinOptions);\n\t\treturn this.spawnPlayer(data);\n\t}\n\n\t/**\n\t * Leaves a voice channel and cleans up the player.\n\t *\n\t * @param guild - The ID of the guild to leave.\n\t * @returns A promise resolving to whether the operation was successful.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Leave a voice channel\n\t * const success = await manager.leave(\"123456789012345678\");\n\t * if (success) {\n\t * console.log(\"Successfully left the voice channel\");\n\t * } else {\n\t * console.log(\"Not in a voice channel in this guild\");\n\t * }\n\t * ```\n\t */\n\tpublic async leave(guild: string): Promise<boolean> {\n\t\tawait this.sendWS(guild, null);\n\t\tconst player = this.players.get(guild);\n\t\tif (!player) return false;\n\n\t\tawait player.destroy();\n\t\treturn this.players.delete(guild);\n\t}\n\n\t/**\n\t * Switches a player from one node to another, implementing fallback capability.\n\t *\n\t * @param player - The player to move to another node.\n\t * @param node - The destination node.\n\t * @returns A promise resolving to the updated player.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Switch a player to another node (e.g. if current node is failing)\n\t * const player = manager.players.get(\"123456789012345678\");\n\t * const newNode = manager.nodes.get(\"backup-node\");\n\t *\n\t * if (player && newNode) {\n\t * await manager.switch(player, newNode);\n\t * console.log(\"Player switched to backup node\");\n\t * }\n\t * ```\n\t */\n\tpublic async switch(player: Player, node: LavalinkNode): Promise<Player> {\n\t\tplayer.node = node;\n\n\t\tif (!player.voice) return player;\n\t\tawait player.destroy();\n\t\tif (!player.track) return player;\n\n\t\tawait player.play(player.track.encoded, {\n\t\t\tposition: player.state.position,\n\t\t\tvolume: player.volume,\n\t\t\tfilters: player.filters,\n\t\t\tvoice: player.voice,\n\t\t\tpaused: player.paused,\n\t\t\tuserData: player.track.userData\n\t\t});\n\n\t\treturn player;\n\t}\n\n\t/**\n\t * Processes voice server update events from Discord.\n\t *\n\t * @param data - The voice server update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => {\n\t * manager.voiceServerUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic voiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): Promise<boolean> {\n\t\tthis.voiceServers.set(data.guild_id, data);\n\t\tthis.expecting.add(data.guild_id);\n\t\treturn this._attemptConnection(data.guild_id);\n\t}\n\n\t/**\n\t * Processes voice state update events from Discord.\n\t *\n\t * @param data - The voice state update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => {\n\t * manager.voiceStateUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic async voiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): Promise<boolean> {\n\t\tif (data.user_id !== this.userId) return false;\n\t\tif (!data.guild_id) return false;\n\n\t\tif (data.channel_id) {\n\t\t\tthis.voiceStates.set(data.guild_id, data);\n\t\t\treturn this._attemptConnection(data.guild_id);\n\t\t}\n\n\t\tthis.voiceServers.delete(data.guild_id);\n\t\tthis.voiceStates.delete(data.guild_id);\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sends a voice state update packet to Discord.\n\t *\n\t * @param guild - The ID of the guild.\n\t * @param channel - The ID of the voice channel to join, or null to leave.\n\t * @param options - Options for joining (selfmute, selfdeaf).\n\t * @returns The result from the send function.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * manager.sendWS(\"123456789012345678\", \"123456789012345679\", { selfdeaf: true });\n\t *\n\t * // Leave a voice channel\n\t * manager.sendWS(\"123456789012345678\", null);\n\t * ```\n\t */\n\tpublic sendWS(guild: string, channel: string | null, { selfmute = false, selfdeaf = false }: JoinOptions = {}): unknown {\n\t\treturn this.send({\n\t\t\top: 4,\n\t\t\td: {\n\t\t\t\tguild_id: guild,\n\t\t\t\tchannel_id: channel,\n\t\t\t\tself_mute: selfmute,\n\t\t\t\tself_deaf: selfdeaf\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets all connected nodes, sorted by CPU load.\n\t *\n\t * @returns An array of connected nodes sorted by CPU load (least to most).\n\t *\n\t * @example\n\t * ```typescript\n\t * // Get the node with the least CPU load\n\t * const bestNode = manager.idealNodes[0];\n\t * if (bestNode) {\n\t * console.log(`Best node for new connections: ${bestNode.id}`);\n\t * }\n\t * ```\n\t */\n\tpublic get idealNodes(): LavalinkNode[] {\n\t\treturn Array.from(this.nodes.values())\n\t\t\t.filter((node) => node.connected)\n\t\t\t.sort((a, b) => {\n\t\t\t\tconst aload = a.stats.cpu ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100 : 0;\n\t\t\t\tconst bload = b.stats.cpu ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100 : 0;\n\t\t\t\treturn aload - bload;\n\t\t\t});\n\t}\n\n\t/**\n\t * Attempts to establish a connection for a guild using available voice data.\n\t *\n\t * @internal\n\t * @param guildID - The ID of the guild to attempt connecting.\n\t * @returns A promise resolving to whether a connection was established.\n\t */\n\tprivate async _attemptConnection(guildID: string): Promise<boolean> {\n\t\tconst server = this.voiceServers.get(guildID);\n\t\tconst state = this.voiceStates.get(guildID);\n\n\t\tif (!server || !state || !this.expecting.has(guildID)) return false;\n\n\t\tconst player = this.players.get(guildID);\n\t\tif (!player) return false;\n\n\t\tawait player.connect({ sessionId: state.session_id, event: server });\n\t\tthis.expecting.delete(guildID);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @internal\n\t * @param data - The data needed to create a player.\n\t * @returns The created Player instance.\n\t */\n\tprivate spawnPlayer(data: JoinData): Player {\n\t\tconst exists = this.players.get(data.guild);\n\t\tif (exists) return exists;\n\t\tconst node = this.nodes.get(data.node);\n\t\tif (!node) throw new Error(`INVALID_HOST: No available node with ${data.node}`);\n\t\tconst player = new this.Player(node, data.guild);\n\t\tthis.players.set(data.guild, player);\n\t\treturn player;\n\t}\n\n\tprotected send(packet: GatewayVoiceStateUpdate): unknown {\n\t\tif (typeof this._send !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a send function to be defined in the Manager options.\\\n\t\t\t\tThis function should send voice state updates to Discord.\"\n\t\t\t);\n\t\t}\n\t\treturn this._send(packet);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/Manager.ts"],"names":[],"mappings":"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","file":"Manager.mjs","sourcesContent":["import { EventEmitter } from \"events\";\nimport { LavalinkNode } from \"./LavalinkNode\";\nimport { Player } from \"./Player\";\nimport type { JoinData, ManagerOptions, JoinOptions, LavalinkNodeOptions, ManagerEvents } from \"./Types\";\nimport { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdate, GatewayVoiceStateUpdateDispatchData } from \"discord-api-types/v10\";\n\n/**\n * Main class that handles Lavalink node connections and player management.\n *\n * @remarks\n * The Manager acts as the central hub for Lavacord, managing connections to Lavalink nodes,\n * handling voice state updates, and providing a unified interface for player operations.\n */\nexport class Manager extends EventEmitter<ManagerEvents> {\n\t/**\n\t * A Map of Lavalink Nodes indexed by their IDs.\n\t */\n\tpublic nodes = new Map<string, LavalinkNode>();\n\n\t/**\n\t * A Map of all active players indexed by guild ID.\n\t */\n\tpublic players = new Map<string, Player>();\n\n\t/**\n\t * A Map of voice server update states indexed by guild ID.\n\t */\n\tpublic voiceServers = new Map<string, GatewayVoiceServerUpdateDispatchData>();\n\n\t/**\n\t * A Map of voice state update states indexed by guild ID.\n\t */\n\tpublic voiceStates = new Map<string, GatewayVoiceStateUpdateDispatchData>();\n\n\t/**\n\t * The user ID of the bot this Manager is managing.\n\t */\n\tpublic userId: string | null = null;\n\n\t/**\n\t * Function to send voice state update packets to Discord.\n\t *\n\t * @remarks\n\t * This can be implemented by the user in two ways:\n\t * 1. Via constructor options: `new Manager(nodes, { send: fn })`\n\t * 2. Via class extension: `class MyManager extends Manager { send(packet) { ... } }`\n\t */\n\tprivate _send?: (packet: GatewayVoiceStateUpdate) => unknown;\n\n\t/**\n\t * The Player class constructor used when creating new players.\n\t *\n\t * @remarks\n\t * Can be overridden in the manager options to use a custom Player implementation.\n\t */\n\tprivate readonly Player: typeof Player = Player;\n\n\t/**\n\t * A Set of guild IDs that are waiting for a connection.\n\t *\n\t * @internal\n\t */\n\tprivate readonly expecting = new Set<string>();\n\n\t/**\n\t * Creates a new Manager instance.\n\t *\n\t * @param nodes - An array of Lavalink node options to connect to.\n\t * @param options - Configuration options for the Manager.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Method 1: Define send function via options\n\t * const manager = new Manager([\n\t * {\n\t * id: \"main\",\n\t * host: \"localhost\",\n\t * port: 2333,\n\t * password: \"youshallnotpass\"\n\t * }\n\t * ], {\n\t * userId: \"bot_user_id\",\n\t * send: (packet) => {\n\t * const guild = client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * });\n\t *\n\t * // Method 2: Extend Manager class\n\t * class MyManager extends Manager {\n\t * send(packet) {\n\t * const guild = this.client.guilds.cache.get(packet.d.guild_id);\n\t * if (guild) guild.shard.send(packet);\n\t * }\n\t * }\n\t * const manager = new MyManager(nodes, { userId: \"bot_user_id\" });\n\t * ```\n\t */\n\tpublic constructor(nodes: LavalinkNodeOptions[], options?: ManagerOptions) {\n\t\tsuper();\n\t\toptions ??= {};\n\n\t\tif (options.userId) this.userId = options.userId;\n\t\tif (options.player) this.Player = options.player;\n\t\tif (options.send && !this._send) this._send = options.send;\n\n\t\tfor (const node of nodes) this.createNode(node);\n\t}\n\n\t/**\n\t * Connects all Lavalink nodes to their respective Lavalink servers.\n\t *\n\t * @returns A promise that resolves when all connections are established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Connect all nodes\n\t * manager.connect()\n\t * .then(() => console.log('All nodes connected!'))\n\t * .catch(error => console.error('Failed to connect nodes:', error));\n\t * ```\n\t */\n\tpublic async connect(): Promise<LavalinkNode[]> {\n\t\tif (!this.userId)\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a client user ID before connecting. \\n\" +\n\t\t\t\t\t\"Set the user ID when constructing the Manager or after your Discord client is ready.\"\n\t\t\t);\n\t\treturn Promise.all(this.nodes.values().map((node) => node.connect().then(() => node)));\n\t}\n\n\t/**\n\t * Disconnects all players and nodes, effectively cleaning up all resources.\n\t *\n\t * @returns A promise that resolves when all disconnections are complete.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Disconnect everything\n\t * manager.disconnect()\n\t * .then(() => console.log('All players and nodes cleaned up'))\n\t * .catch(error => console.error('Error during disconnection:', error));\n\t * ```\n\t */\n\tpublic async disconnect(): Promise<void> {\n\t\tfor await (const player of this.players.keys()) await this.leave(player);\n\t\tfor (const node of this.nodes.values()) node.destroy();\n\t}\n\n\t/**\n\t * Creates a new Lavalink node and adds it to the nodes map.\n\t *\n\t * @param options - Configuration options for the node.\n\t * @returns The newly created LavalinkNode instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Add a new node\n\t * const newNode = manager.createNode({\n\t * id: \"node2\",\n\t * host: \"example.com\",\n\t * port: 2333,\n\t * password: \"securepassword\",\n\t * resuming: true\n\t * });\n\t * ```\n\t */\n\tpublic createNode(options: LavalinkNodeOptions): LavalinkNode {\n\t\tconst node = new LavalinkNode(this, options);\n\t\tthis.nodes.set(options.id, node);\n\t\treturn node;\n\t}\n\n\t/**\n\t * Disconnects and removes a node from the manager.\n\t *\n\t * @param id - The ID of the node to remove.\n\t * @returns Whether the node was successfully removed.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Remove a node\n\t * const removed = manager.removeNode(\"node1\");\n\t * if (removed) {\n\t * console.log(\"Node successfully removed\");\n\t * } else {\n\t * console.log(\"Node not found\");\n\t * }\n\t * ```\n\t */\n\tpublic removeNode(id: string): boolean {\n\t\tconst node = this.nodes.get(id);\n\t\tif (!node) return false;\n\t\tnode.destroy();\n\t\treturn this.nodes.delete(id);\n\t}\n\n\t/**\n\t * Joins a voice channel and creates a player for the guild.\n\t *\n\t * @param data - The data needed to join a voice channel.\n\t * @param joinOptions - Options for joining the channel (selfmute, selfdeaf).\n\t * @returns A promise resolving to the Player instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * const player = await manager.join({\n\t * guild: \"123456789012345678\", // Guild ID\n\t * channel: \"123456789012345679\", // Voice Channel ID\n\t * node: \"main\" // Node ID\n\t * }, {\n\t * selfdeaf: true // Join deafened\n\t * });\n\t *\n\t * // Now you can use the player to play music\n\t * const result = await Rest.load(player.node, \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\");\n\t * await player.play(result.tracks[0].track);\n\t * ```\n\t */\n\tpublic async join(data: JoinData, joinOptions: JoinOptions = {}): Promise<Player> {\n\t\tconst player = this.players.get(data.guild);\n\t\tif (player) return player;\n\t\tawait this.sendWS(data.guild, data.channel, joinOptions);\n\t\treturn this.spawnPlayer(data);\n\t}\n\n\t/**\n\t * Leaves a voice channel and cleans up the player.\n\t *\n\t * @param guild - The ID of the guild to leave.\n\t * @returns A promise resolving to whether the operation was successful.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Leave a voice channel\n\t * const success = await manager.leave(\"123456789012345678\");\n\t * if (success) {\n\t * console.log(\"Successfully left the voice channel\");\n\t * } else {\n\t * console.log(\"Not in a voice channel in this guild\");\n\t * }\n\t * ```\n\t */\n\tpublic async leave(guild: string): Promise<boolean> {\n\t\tawait this.sendWS(guild, null);\n\t\tconst player = this.players.get(guild);\n\t\tif (!player) return false;\n\n\t\tawait player.destroy();\n\t\treturn this.players.delete(guild);\n\t}\n\n\t/**\n\t * Switches a player from one node to another, implementing fallback capability.\n\t *\n\t * @param player - The player to move to another node.\n\t * @param node - The destination node.\n\t * @returns A promise resolving to the updated player.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Switch a player to another node (e.g. if current node is failing)\n\t * const player = manager.players.get(\"123456789012345678\");\n\t * const newNode = manager.nodes.get(\"backup-node\");\n\t *\n\t * if (player && newNode) {\n\t * await manager.switch(player, newNode);\n\t * console.log(\"Player switched to backup node\");\n\t * }\n\t * ```\n\t */\n\tpublic async switch(player: Player, node: LavalinkNode): Promise<Player> {\n\t\tplayer.node = node;\n\n\t\tif (!player.voice?.channelId) return player;\n\t\tawait player.destroy();\n\t\tif (!player.track) return player;\n\n\t\tawait player.play(player.track.encoded, {\n\t\t\tposition: player.state.position,\n\t\t\tvolume: player.volume,\n\t\t\tfilters: player.filters,\n\t\t\t// @ts-expect-error The type narrow for if no channelId didn't work\n\t\t\tvoice: player.voice,\n\t\t\tpaused: player.paused,\n\t\t\tuserData: player.track.userData\n\t\t});\n\n\t\treturn player;\n\t}\n\n\t/**\n\t * Processes voice server update events from Discord.\n\t *\n\t * @param data - The voice server update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceServerUpdate, (data) => {\n\t * manager.voiceServerUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic voiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): Promise<boolean> {\n\t\tthis.voiceServers.set(data.guild_id, data);\n\t\tthis.expecting.add(data.guild_id);\n\t\treturn this._attemptConnection(data.guild_id);\n\t}\n\n\t/**\n\t * Processes voice state update events from Discord.\n\t *\n\t * @param data - The voice state update data from Discord.\n\t * @returns A promise resolving to whether a connection was established.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In your Discord.js client events\n\t * client.ws.on(GatewayDispatchEvents.VoiceStateUpdate, (data) => {\n\t * manager.voiceStateUpdate(data);\n\t * });\n\t * ```\n\t */\n\tpublic async voiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): Promise<boolean> {\n\t\tif (data.user_id !== this.userId) return false;\n\t\tif (!data.guild_id) return false;\n\n\t\tif (data.channel_id) {\n\t\t\tthis.voiceStates.set(data.guild_id, data);\n\t\t\treturn this._attemptConnection(data.guild_id);\n\t\t}\n\n\t\tthis.voiceServers.delete(data.guild_id);\n\t\tthis.voiceStates.delete(data.guild_id);\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sends a voice state update packet to Discord.\n\t *\n\t * @param guild - The ID of the guild.\n\t * @param channel - The ID of the voice channel to join, or null to leave.\n\t * @param options - Options for joining (selfmute, selfdeaf).\n\t * @returns The result from the send function.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Join a voice channel\n\t * manager.sendWS(\"123456789012345678\", \"123456789012345679\", { selfdeaf: true });\n\t *\n\t * // Leave a voice channel\n\t * manager.sendWS(\"123456789012345678\", null);\n\t * ```\n\t */\n\tpublic sendWS(guild: string, channel: string | null, { selfmute = false, selfdeaf = false }: JoinOptions = {}): unknown {\n\t\treturn this.send({\n\t\t\top: 4,\n\t\t\td: {\n\t\t\t\tguild_id: guild,\n\t\t\t\tchannel_id: channel,\n\t\t\t\tself_mute: selfmute,\n\t\t\t\tself_deaf: selfdeaf\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets all connected nodes, sorted by CPU load.\n\t *\n\t * @returns An array of connected nodes sorted by CPU load (least to most).\n\t *\n\t * @example\n\t * ```typescript\n\t * // Get the node with the least CPU load\n\t * const bestNode = manager.idealNodes[0];\n\t * if (bestNode) {\n\t * console.log(`Best node for new connections: ${bestNode.id}`);\n\t * }\n\t * ```\n\t */\n\tpublic get idealNodes(): LavalinkNode[] {\n\t\treturn Array.from(this.nodes.values())\n\t\t\t.filter((node) => node.connected)\n\t\t\t.sort((a, b) => {\n\t\t\t\tconst aload = a.stats.cpu ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100 : 0;\n\t\t\t\tconst bload = b.stats.cpu ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100 : 0;\n\t\t\t\treturn aload - bload;\n\t\t\t});\n\t}\n\n\t/**\n\t * Attempts to establish a connection for a guild using available voice data.\n\t *\n\t * @internal\n\t * @param guildID - The ID of the guild to attempt connecting.\n\t * @returns A promise resolving to whether a connection was established.\n\t */\n\tprivate async _attemptConnection(guildID: string): Promise<boolean> {\n\t\tconst server = this.voiceServers.get(guildID);\n\t\tconst state = this.voiceStates.get(guildID);\n\n\t\tif (!server || !state || !this.expecting.has(guildID)) return false;\n\n\t\tconst player = this.players.get(guildID);\n\t\tif (!player) return false;\n\n\t\tawait player.connect({ sessionId: state.session_id, event: server, channelId: state.channel_id! });\n\t\tthis.expecting.delete(guildID);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @internal\n\t * @param data - The data needed to create a player.\n\t * @returns The created Player instance.\n\t */\n\tprivate spawnPlayer(data: JoinData): Player {\n\t\tconst exists = this.players.get(data.guild);\n\t\tif (exists) return exists;\n\t\tconst node = this.nodes.get(data.node);\n\t\tif (!node) throw new Error(`INVALID_HOST: No available node with ${data.node}`);\n\t\tconst player = new this.Player(node, data.guild);\n\t\tthis.players.set(data.guild, player);\n\t\treturn player;\n\t}\n\n\tprotected send(packet: GatewayVoiceStateUpdate): unknown {\n\t\tif (typeof this._send !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"Lavacord requires a send function to be defined in the Manager options.\\\n\t\t\t\tThis function should send voice state updates to Discord.\"\n\t\t\t);\n\t\t}\n\t\treturn this._send(packet);\n\t}\n}\n"]}
|
package/dist/esm/lib/Player.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/Player.ts"],"names":[],"mappings":"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","file":"Player.mjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { EventEmitter } from \"events\";\nimport { Rest } from \"./Rest\";\nimport type { LavalinkNode } from \"./LavalinkNode\";\nimport type { Manager } from \"./Manager\";\nimport type { PlayerUpdateVoiceState, JoinOptions, PlayerEvents } from \"./Types\";\nimport {\n\tPlayerState,\n\tTrack,\n\tVoiceState,\n\tFilters,\n\tUpdatePlayerData,\n\tUpdatePlayerResult,\n\tEqualizer,\n\tDestroyPlayerResult,\n\tPlayer as APIPlayer\n} from \"lavalink-types\";\n\n/**\n * The Player class that handles playback and audio manipulation for a specific guild.\n *\n * @remarks\n * This class is responsible for audio playback operations, including playing, stopping,\n * pausing, resuming, and applying audio filters. Each instance represents a player\n * for a specific guild.\n */\nexport class Player extends EventEmitter<PlayerEvents> {\n\t/**\n\t * The current state of this Player\n\t *\n\t * @remarks\n\t * Contains information about the player state from Lavalink, including position, filters, etc.\n\t */\n\tpublic state: PlayerState = {\n\t\ttime: 0,\n\t\tposition: 0,\n\t\tconnected: false,\n\t\tping: 0\n\t};\n\t/**\n\t * The timestamp when the current track started playing\n\t *\n\t * @remarks\n\t * This is a client-side timestamp, not synchronized with Lavalink.\n\t * Can be used to calculate approximate playback position.\n\t */\n\tpublic timestamp: number | null = null;\n\t/**\n\t * Whether the audio playback is currently paused\n\t */\n\tpublic paused = false;\n\t/**\n\t * The current volume level (0-1000)\n\t */\n\tpublic volume = 100;\n\t/**\n\t * The current track in Lavalink's base64 string form\n\t *\n\t * @remarks\n\t * This is null when no track is loaded or when playback has ended.\n\t */\n\tpublic track: Track | null = null;\n\t/**\n\t * The voice connection state from Lavalink API\n\t */\n\tpublic voice: VoiceState | null = null;\n\t/**\n\t * The current audio filters applied to this player\n\t *\n\t * @remarks\n\t * This includes effects like equalizer, karaoke, etc.\n\t */\n\tpublic filters: Filters = {};\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @param node - The Lavalink node this player is connected to.\n\t * @param guildId - The guild ID that this player is associated with.\n\t */\n\tpublic constructor(\n\t\t/**\n\t\t * The Lavalink node this player is connected to\n\t\t */\n\t\tpublic node: LavalinkNode,\n\t\t/**\n\t\t * The guild ID for this player\n\t\t */\n\t\tpublic guildId: string\n\t) {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Updates the current player on the Lavalink node.\n\t * @see {@link https://lavalink.dev/api/rest#update-player}\n\t *\n\t * @param options - The update options to apply to the player.\n\t * @param noReplace - If true, the event will be dropped if there's a currently playing track.\n\t * @returns {Promise<APIPlayer>} The updated player information from Lavalink.\n\t */\n\tpublic async update(options: UpdatePlayerData, noReplace = false): Promise<APIPlayer> {\n\t\tconst d = await Rest.updatePlayer(this.node, this.guildId, options, noReplace);\n\n\t\t// Update local state with response data\n\t\tif (\"track\" in d) this.track = d.track;\n\t\tif (\"volume\" in d) this.volume = d.volume;\n\t\tif (\"paused\" in d) this.paused = d.paused;\n\t\tif (\"state\" in d) this.state = d.state;\n\t\tif (\"filters\" in d) this.filters = d.filters;\n\t\tif (\"voice\" in d) this.voice = d.voice;\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Plays a track using its base64 encoded string.\n\t *\n\t * @param track - The base64 encoded track string from Lavalink.\n\t * @param options - Additional options for playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async play(\n\t\ttrack: string,\n\t\toptions?: Omit<UpdatePlayerData, \"track\"> & {\n\t\t\tnoReplace?: boolean;\n\t\t\tuserData?: Record<any, any>;\n\t\t}\n\t): Promise<UpdatePlayerResult> {\n\t\tconst { userData, noReplace, ...opts } = options || {};\n\n\t\tconst d = await this.update({ track: { encoded: track, userData }, ...opts }, noReplace ?? false);\n\t\tthis.timestamp = Date.now();\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Stops the currently playing track.\n\t *\n\t * @remarks\n\t * This will trigger a \"TrackEndEvent\" with reason \"STOPPED\".\n\t *\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic stop(): Promise<UpdatePlayerResult> {\n\t\treturn this.update({ track: { encoded: null } });\n\t}\n\n\t/**\n\t * Pauses or resumes the current track.\n\t *\n\t * @param pause - Whether to pause (true) or resume (false) playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async pause(pause: boolean): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ paused: pause });\n\t\tif (this.listenerCount(\"pause\")) this.emit(\"pause\", pause);\n\t\tif (this.manager.listenerCount(\"playerPause\")) this.manager.emit(\"playerPause\", this, pause);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Changes the volume of the current playback.\n\t *\n\t * @param volume - The volume level as a number between 0 and 1000\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setVolume(volume: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ volume });\n\t\tif (this.listenerCount(\"volume\")) this.emit(\"volume\", volume);\n\t\tif (this.manager.listenerCount(\"playerVolume\")) this.manager.emit(\"playerVolume\", this, volume);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Seeks to a specific position in the current track.\n\t *\n\t * @param position - The position to seek to in milliseconds.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async seek(position: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ position });\n\t\tif (this.listenerCount(\"seek\")) this.emit(\"seek\", position);\n\t\tif (this.manager.listenerCount(\"playerSeek\")) this.manager.emit(\"playerSeek\", this, position);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Applies audio filters to the current playback.\n\t *\n\t * @param options - The filter options to apply.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setFilters(options: Filters): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ filters: options });\n\t\tif (this.listenerCount(\"filters\")) this.emit(\"filters\", options);\n\t\tif (this.manager.listenerCount(\"playerFilters\")) this.manager.emit(\"playerFilters\", this, options);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Sets the equalizer effect for the current playback.\n\t *\n\t * @param bands - An array of equalizer bands to adjust.\n\t * @returns A promise resolving to the updated player information.\n\t *\n\t * @remarks\n\t * Each band is an object with 'band' (0-14) and 'gain' (-0.25 to 1.0) properties.\n\t */\n\tpublic async setEqualizer(bands: Equalizer[]): Promise<UpdatePlayerResult> {\n\t\treturn this.setFilters({ equalizer: bands });\n\t}\n\n\t/**\n\t * Destroys the player on the Lavalink node.\n\t *\n\t * @remarks\n\t * This sends a destroy signal to Lavalink to clean up resources for this guild ID.\n\t * It doesn't affect the Discord voice connection - use {@link Manager.leave} for that.\n\t *\n\t * @returns {Promise<DestroyPlayerResult>} A promise resolving to the destroy result.\n\t */\n\tpublic async destroy(): Promise<DestroyPlayerResult> {\n\t\treturn Rest.destroyPlayer(this.node, this.guildId);\n\t}\n\n\t/**\n\t * Provides voice server update information to Lavalink to establish a connection.\n\t *\n\t * @param data - The voice update state containing session ID and voice server information.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic connect(data: PlayerUpdateVoiceState): Promise<UpdatePlayerResult> {\n\t\treturn this.update({\n\t\t\tvoice: {\n\t\t\t\ttoken: data.event.token,\n\t\t\t\tendpoint: data.event.endpoint,\n\t\t\t\tsessionId: data.sessionId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Switches the player to a different voice channel.\n\t *\n\t * @param channel - The ID of the voice channel to switch to.\n\t * @param options - Options for joining the channel (selfMute, selfDeaf).\n\t * @returns Does not return anything, but sends a WebSocket message to the Lavalink node.\n\t */\n\tpublic switchChannel(channel: string, options: JoinOptions = {}): unknown {\n\t\treturn this.manager.sendWS(this.guildId, channel, options);\n\t}\n\n\t/**\n\t * Gets the manager instance that created this player.\n\t *\n\t * @returns {Manager} The manager instance.\n\t */\n\tpublic get manager(): Manager {\n\t\treturn this.node.manager;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/Player.ts"],"names":[],"mappings":"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","file":"Player.mjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { EventEmitter } from \"events\";\nimport { Rest } from \"./Rest\";\nimport type { LavalinkNode } from \"./LavalinkNode\";\nimport type { Manager } from \"./Manager\";\nimport type { PlayerUpdateVoiceState, JoinOptions, PlayerEvents } from \"./Types\";\nimport {\n\tPlayerState,\n\tTrack,\n\tVoiceState,\n\tFilters,\n\tUpdatePlayerData,\n\tUpdatePlayerResult,\n\tEqualizer,\n\tDestroyPlayerResult,\n\tPlayer as APIPlayer\n} from \"lavalink-types\";\n\n/**\n * The Player class that handles playback and audio manipulation for a specific guild.\n *\n * @remarks\n * This class is responsible for audio playback operations, including playing, stopping,\n * pausing, resuming, and applying audio filters. Each instance represents a player\n * for a specific guild.\n */\nexport class Player extends EventEmitter<PlayerEvents> {\n\t/**\n\t * The current state of this Player\n\t *\n\t * @remarks\n\t * Contains information about the player state from Lavalink, including position, filters, etc.\n\t */\n\tpublic state: PlayerState = {\n\t\ttime: 0,\n\t\tposition: 0,\n\t\tconnected: false,\n\t\tping: 0\n\t};\n\t/**\n\t * The timestamp when the current track started playing\n\t *\n\t * @remarks\n\t * This is a client-side timestamp, not synchronized with Lavalink.\n\t * Can be used to calculate approximate playback position.\n\t */\n\tpublic timestamp: number | null = null;\n\t/**\n\t * Whether the audio playback is currently paused\n\t */\n\tpublic paused = false;\n\t/**\n\t * The current volume level (0-1000)\n\t */\n\tpublic volume = 100;\n\t/**\n\t * The current track in Lavalink's base64 string form\n\t *\n\t * @remarks\n\t * This is null when no track is loaded or when playback has ended.\n\t */\n\tpublic track: Track | null = null;\n\t/**\n\t * The voice connection state from Lavalink API\n\t */\n\tpublic voice: VoiceState | null = null;\n\t/**\n\t * The current audio filters applied to this player\n\t *\n\t * @remarks\n\t * This includes effects like equalizer, karaoke, etc.\n\t */\n\tpublic filters: Filters = {};\n\n\t/**\n\t * Creates a new player instance.\n\t *\n\t * @param node - The Lavalink node this player is connected to.\n\t * @param guildId - The guild ID that this player is associated with.\n\t */\n\tpublic constructor(\n\t\t/**\n\t\t * The Lavalink node this player is connected to\n\t\t */\n\t\tpublic node: LavalinkNode,\n\t\t/**\n\t\t * The guild ID for this player\n\t\t */\n\t\tpublic guildId: string\n\t) {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Updates the current player on the Lavalink node.\n\t * @see {@link https://lavalink.dev/api/rest#update-player}\n\t *\n\t * @param options - The update options to apply to the player.\n\t * @param noReplace - If true, the event will be dropped if there's a currently playing track.\n\t * @returns {Promise<APIPlayer>} The updated player information from Lavalink.\n\t */\n\tpublic async update(options: UpdatePlayerData, noReplace = false): Promise<APIPlayer> {\n\t\tconst d = await Rest.updatePlayer(this.node, this.guildId, options, noReplace);\n\n\t\t// Update local state with response data\n\t\tif (\"track\" in d) this.track = d.track;\n\t\tif (\"volume\" in d) this.volume = d.volume;\n\t\tif (\"paused\" in d) this.paused = d.paused;\n\t\tif (\"state\" in d) this.state = d.state;\n\t\tif (\"filters\" in d) this.filters = d.filters;\n\t\tif (\"voice\" in d) this.voice = d.voice;\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Plays a track using its base64 encoded string.\n\t *\n\t * @param track - The base64 encoded track string from Lavalink.\n\t * @param options - Additional options for playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async play(\n\t\ttrack: string,\n\t\toptions?: Omit<UpdatePlayerData, \"track\"> & {\n\t\t\tnoReplace?: boolean;\n\t\t\tuserData?: Record<any, any>;\n\t\t}\n\t): Promise<UpdatePlayerResult> {\n\t\tconst { userData, noReplace, ...opts } = options || {};\n\n\t\tconst d = await this.update({ track: { encoded: track, userData }, ...opts }, noReplace ?? false);\n\t\tthis.timestamp = Date.now();\n\n\t\treturn d;\n\t}\n\n\t/**\n\t * Stops the currently playing track.\n\t *\n\t * @remarks\n\t * This will trigger a \"TrackEndEvent\" with reason \"STOPPED\".\n\t *\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic stop(): Promise<UpdatePlayerResult> {\n\t\treturn this.update({ track: { encoded: null } });\n\t}\n\n\t/**\n\t * Pauses or resumes the current track.\n\t *\n\t * @param pause - Whether to pause (true) or resume (false) playback.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async pause(pause: boolean): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ paused: pause });\n\t\tif (this.listenerCount(\"pause\")) this.emit(\"pause\", pause);\n\t\tif (this.manager.listenerCount(\"playerPause\")) this.manager.emit(\"playerPause\", this, pause);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Changes the volume of the current playback.\n\t *\n\t * @param volume - The volume level as a number between 0 and 1000\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setVolume(volume: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ volume });\n\t\tif (this.listenerCount(\"volume\")) this.emit(\"volume\", volume);\n\t\tif (this.manager.listenerCount(\"playerVolume\")) this.manager.emit(\"playerVolume\", this, volume);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Seeks to a specific position in the current track.\n\t *\n\t * @param position - The position to seek to in milliseconds.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async seek(position: number): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ position });\n\t\tif (this.listenerCount(\"seek\")) this.emit(\"seek\", position);\n\t\tif (this.manager.listenerCount(\"playerSeek\")) this.manager.emit(\"playerSeek\", this, position);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Applies audio filters to the current playback.\n\t *\n\t * @param options - The filter options to apply.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic async setFilters(options: Filters): Promise<UpdatePlayerResult> {\n\t\tconst d = await this.update({ filters: options });\n\t\tif (this.listenerCount(\"filters\")) this.emit(\"filters\", options);\n\t\tif (this.manager.listenerCount(\"playerFilters\")) this.manager.emit(\"playerFilters\", this, options);\n\t\treturn d;\n\t}\n\n\t/**\n\t * Sets the equalizer effect for the current playback.\n\t *\n\t * @param bands - An array of equalizer bands to adjust.\n\t * @returns A promise resolving to the updated player information.\n\t *\n\t * @remarks\n\t * Each band is an object with 'band' (0-14) and 'gain' (-0.25 to 1.0) properties.\n\t */\n\tpublic async setEqualizer(bands: Equalizer[]): Promise<UpdatePlayerResult> {\n\t\treturn this.setFilters({ equalizer: bands });\n\t}\n\n\t/**\n\t * Destroys the player on the Lavalink node.\n\t *\n\t * @remarks\n\t * This sends a destroy signal to Lavalink to clean up resources for this guild ID.\n\t * It doesn't affect the Discord voice connection - use {@link Manager.leave} for that.\n\t *\n\t * @returns {Promise<DestroyPlayerResult>} A promise resolving to the destroy result.\n\t */\n\tpublic async destroy(): Promise<DestroyPlayerResult> {\n\t\treturn Rest.destroyPlayer(this.node, this.guildId);\n\t}\n\n\t/**\n\t * Provides voice server update information to Lavalink to establish a connection.\n\t *\n\t * @param data - The voice update state containing session ID and voice server information.\n\t * @returns A promise resolving to the updated player information.\n\t */\n\tpublic connect(data: PlayerUpdateVoiceState): Promise<UpdatePlayerResult> {\n\t\treturn this.update({\n\t\t\tvoice: {\n\t\t\t\ttoken: data.event.token,\n\t\t\t\tendpoint: data.event.endpoint,\n\t\t\t\tsessionId: data.sessionId,\n\t\t\t\tchannelId: data.channelId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Switches the player to a different voice channel.\n\t *\n\t * @param channel - The ID of the voice channel to switch to.\n\t * @param options - Options for joining the channel (selfMute, selfDeaf).\n\t * @returns Does not return anything, but sends a WebSocket message to the Lavalink node.\n\t */\n\tpublic switchChannel(channel: string, options: JoinOptions = {}): unknown {\n\t\treturn this.manager.sendWS(this.guildId, channel, options);\n\t}\n\n\t/**\n\t * Gets the manager instance that created this player.\n\t *\n\t * @returns {Manager} The manager instance.\n\t */\n\tpublic get manager(): Manager {\n\t\treturn this.node.manager;\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lavacord",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A simple by design lavalink wrapper made for any discord library.",
|
|
5
5
|
"main": "./dist/cjs/index.cjs",
|
|
6
6
|
"module": "./dist/esm/index.mjs",
|
|
@@ -84,28 +84,28 @@
|
|
|
84
84
|
"homepage": "https://github.com/lavacord/lavacord#readme",
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"cloudstorm": "^0.17.0",
|
|
87
|
-
"discord-api-types": "^0.38.
|
|
88
|
-
"lavalink-types": "^3.
|
|
87
|
+
"discord-api-types": "^0.38.42",
|
|
88
|
+
"lavalink-types": "^3.1.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
|
-
"@eslint/js": "^9.39.
|
|
91
|
+
"@eslint/js": "^9.39.4",
|
|
92
92
|
"@favware/rollup-type-bundler": "^4.0.0",
|
|
93
|
-
"@types/node": "^25.
|
|
93
|
+
"@types/node": "^25.4.0",
|
|
94
94
|
"esbuild-plugin-file-path-extensions": "^2.1.4",
|
|
95
95
|
"esbuild-plugin-version-injector": "^1.2.1",
|
|
96
|
-
"eslint": "^9.39.
|
|
96
|
+
"eslint": "^9.39.4",
|
|
97
97
|
"prettier": "^3.8.1",
|
|
98
98
|
"tsup": "^8.5.1",
|
|
99
99
|
"typedoc": "^0.28.17",
|
|
100
100
|
"typedoc-github-theme": "^0.4.0",
|
|
101
101
|
"typescript": "^5.9.3",
|
|
102
|
-
"typescript-eslint": "^8.
|
|
102
|
+
"typescript-eslint": "^8.57.0"
|
|
103
103
|
},
|
|
104
104
|
"optionalDependencies": {
|
|
105
105
|
"detritus-client": "0.16.x",
|
|
106
106
|
"discord.js": "14.x",
|
|
107
107
|
"eris": "0.18.x",
|
|
108
|
-
"oceanic.js": "1.
|
|
108
|
+
"oceanic.js": "1.14.0"
|
|
109
109
|
},
|
|
110
110
|
"packageManager": "yarn@4.12.0"
|
|
111
111
|
}
|