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.
@@ -7,7 +7,7 @@ var Rest_cjs = require('./lib/Rest.cjs');
7
7
  var Types_cjs = require('./lib/Types.cjs');
8
8
 
9
9
  // src/index.ts
10
- var VERSION = "3.0.1";
10
+ var VERSION = "3.1.0";
11
11
 
12
12
  exports.VERSION = VERSION;
13
13
  Object.keys(LavalinkNode_cjs).forEach(function (k) {
@@ -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\";\n"]}
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"]}
@@ -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.
@@ -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"]}
@@ -191,7 +191,8 @@ var Player = class extends events.EventEmitter {
191
191
  voice: {
192
192
  token: data.event.token,
193
193
  endpoint: data.event.endpoint,
194
- sessionId: data.sessionId
194
+ sessionId: data.sessionId,
195
+ channelId: data.channelId
195
196
  }
196
197
  });
197
198
  }
@@ -1 +1 @@
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}\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"]}
@@ -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.
@@ -5,7 +5,7 @@ export * from './lib/Manager.mjs';
5
5
  export * from './lib/Rest.mjs';
6
6
  export * from './lib/Types.mjs';
7
7
 
8
- var VERSION = "3.0.1";
8
+ var VERSION = "3.1.0";
9
9
 
10
10
  export { VERSION };
11
11
  //# sourceMappingURL=index.mjs.map
@@ -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\";\n"]}
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"]}
@@ -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":"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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) 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"]}
@@ -188,7 +188,8 @@ var Player = class extends EventEmitter {
188
188
  voice: {
189
189
  token: data.event.token,
190
190
  endpoint: data.event.endpoint,
191
- sessionId: data.sessionId
191
+ sessionId: data.sessionId,
192
+ channelId: data.channelId
192
193
  }
193
194
  });
194
195
  }
@@ -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.1",
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.40",
88
- "lavalink-types": "^3.0.0"
87
+ "discord-api-types": "^0.38.42",
88
+ "lavalink-types": "^3.1.0"
89
89
  },
90
90
  "devDependencies": {
91
- "@eslint/js": "^9.39.3",
91
+ "@eslint/js": "^9.39.4",
92
92
  "@favware/rollup-type-bundler": "^4.0.0",
93
- "@types/node": "^25.3.2",
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.3",
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.56.1"
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.13.0"
108
+ "oceanic.js": "1.14.0"
109
109
  },
110
110
  "packageManager": "yarn@4.12.0"
111
111
  }