lavacord 2.2.0 → 3.0.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.
Files changed (59) hide show
  1. package/LICENSE +24 -201
  2. package/README.md +473 -69
  3. package/dist/cjs/index.cjs +44 -0
  4. package/dist/cjs/index.cjs.map +1 -0
  5. package/dist/cjs/index.d.cts +1211 -0
  6. package/dist/cjs/lib/LavalinkNode.cjs +423 -0
  7. package/dist/cjs/lib/LavalinkNode.cjs.map +1 -0
  8. package/dist/cjs/lib/Manager.cjs +405 -0
  9. package/dist/cjs/lib/Manager.cjs.map +1 -0
  10. package/dist/cjs/lib/Player.cjs +220 -0
  11. package/dist/cjs/lib/Player.cjs.map +1 -0
  12. package/dist/cjs/lib/Rest.cjs +192 -0
  13. package/dist/cjs/lib/Rest.cjs.map +1 -0
  14. package/dist/cjs/lib/Types.cjs +4 -0
  15. package/dist/cjs/lib/Types.cjs.map +1 -0
  16. package/dist/cjs/wrappers/cloudstorm.cjs +54 -0
  17. package/dist/cjs/wrappers/cloudstorm.cjs.map +1 -0
  18. package/dist/cjs/wrappers/detritus.cjs +57 -0
  19. package/dist/cjs/wrappers/detritus.cjs.map +1 -0
  20. package/dist/cjs/wrappers/discord.js.cjs +37 -0
  21. package/dist/cjs/wrappers/discord.js.cjs.map +1 -0
  22. package/dist/cjs/wrappers/eris.cjs +51 -0
  23. package/dist/cjs/wrappers/eris.cjs.map +1 -0
  24. package/dist/cjs/wrappers/oceanic.cjs +52 -0
  25. package/dist/cjs/wrappers/oceanic.cjs.map +1 -0
  26. package/dist/esm/chunk-PAWJFY3S.mjs +6 -0
  27. package/dist/esm/chunk-PAWJFY3S.mjs.map +1 -0
  28. package/dist/esm/index.d.mts +1211 -0
  29. package/dist/esm/index.mjs +12 -0
  30. package/dist/esm/index.mjs.map +1 -0
  31. package/dist/esm/lib/LavalinkNode.mjs +420 -0
  32. package/dist/esm/lib/LavalinkNode.mjs.map +1 -0
  33. package/dist/esm/lib/Manager.mjs +402 -0
  34. package/dist/esm/lib/Manager.mjs.map +1 -0
  35. package/dist/esm/lib/Player.mjs +217 -0
  36. package/dist/esm/lib/Player.mjs.map +1 -0
  37. package/dist/esm/lib/Rest.mjs +188 -0
  38. package/dist/esm/lib/Rest.mjs.map +1 -0
  39. package/dist/esm/lib/Types.mjs +3 -0
  40. package/dist/esm/lib/Types.mjs.map +1 -0
  41. package/dist/esm/wrappers/cloudstorm.mjs +45 -0
  42. package/dist/esm/wrappers/cloudstorm.mjs.map +1 -0
  43. package/dist/esm/wrappers/detritus.mjs +48 -0
  44. package/dist/esm/wrappers/detritus.mjs.map +1 -0
  45. package/dist/esm/wrappers/discord.js.mjs +28 -0
  46. package/dist/esm/wrappers/discord.js.mjs.map +1 -0
  47. package/dist/esm/wrappers/eris.mjs +42 -0
  48. package/dist/esm/wrappers/eris.mjs.map +1 -0
  49. package/dist/esm/wrappers/oceanic.mjs +43 -0
  50. package/dist/esm/wrappers/oceanic.mjs.map +1 -0
  51. package/dist/lib/LavalinkNode.d.ts +3 -3
  52. package/dist/lib/LavalinkNode.js +16 -26
  53. package/dist/lib/LavalinkNode.js.map +1 -1
  54. package/dist/lib/Manager.d.ts +2 -2
  55. package/dist/lib/Manager.js.map +1 -1
  56. package/dist/lib/Rest.js +5 -7
  57. package/dist/lib/Rest.js.map +1 -1
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +109 -64
package/README.md CHANGED
@@ -1,116 +1,520 @@
1
- [![Discord](https://discordapp.com/api/guilds/323779330033319941/embed.png)](https://discord.gg/wXrjZmV)
2
- [![npm (scoped)](https://img.shields.io/npm/v/lavacord?label=npm%20version)](https://www.npmjs.com/package/lavacord)
3
- [![npm downloads](https://img.shields.io/npm/dt/lavacord.svg?label=total%20downloads)](https://www.npmjs.com/package/lavacord)
4
- [![GitHub](https://img.shields.io/github/license/lavacord/lavacord)](https://github.com/lavacord/lavacord/)
5
- [![Depfu](https://badges.depfu.com/badges/70051aad57dddc0c44a990d26b1f6e23/overview.svg)](https://depfu.com/github/lavacord/Lavacord?project_id=11810)
6
- [![Codacy Badge](https://api.codacy.com/project/badge/Grade/b50839d781c24a94a4e1c17342a147bd)](https://www.codacy.com/app/lavacord/lavacord)
1
+ <div align="center" style="padding-bottom: 1rem">
7
2
 
8
- # LavaCord
9
- A simple and easy to use lavalink wrapper.
3
+ <img src="https://github.com/lavacord/Lavacord/blob/gh-pages/assets/Lavacordlogotransparent.png?raw=true" alt="Lavacord Logo" height="200">
10
4
 
11
- ## Documentation
12
- [**lavacord.github.io/lavacord**](https://lavacord.github.io/Lavacord/)
5
+ <p>Lightweight and efficient Lavalink client for Node.js built with TypeScript</p>
13
6
 
14
- ## Installation
7
+ [![npm version](https://img.shields.io/npm/v/lavacord)](https://npmjs.com/package/lavacord)
8
+ [![npm downloads](https://img.shields.io/npm/dt/lavacord)](https://npmjs.com/package/lavacord)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-ready-blue)](https://www.typescriptlang.org/)
10
+ [![License](https://img.shields.io/github/license/lavacord/lavacord)](LICENSE)
11
+
12
+ [![Discord](https://discordapp.com/api/guilds/690521477514264577/embed.png?style=banner2)](https://discord.gg/wXrjZmV)
13
+
14
+ [**Click here for the documentation**](https://lavacord.js.org/)
15
+
16
+ </div>
17
+
18
+ <details>
19
+ <summary>Table of Contents</summary>
20
+
21
+ - [Features](#features)
22
+ - [Installation](#installation)
23
+ - [Quick Start](#quick-start)
24
+ - [Lavalink Node Configuration](#lavalink-node-configuration)
25
+ - [Supported Discord Libraries](#supported-discord-libraries)
26
+ - [Wrapper Example](#wrapper-example)
27
+ - [Basic Usage](#basic-usage)
28
+ - [Search Examples](#search-examples)
29
+ - [Advanced Usage](#advanced-usage)
30
+ - [Player Controls](#player-controls)
31
+ - [Audio Filters](#audio-filters)
32
+ - [Error Handling](#error-handling)
33
+ - [Multiple Nodes & Load Balancing](#multiple-nodes--load-balancing)
34
+ - [Events](#events)
35
+ - [Donate](#donate)
36
+ - [Contributors](#contributors)
37
+
38
+ </details>
39
+
40
+ <br>
41
+
42
+ # Features
43
+
44
+ - Supports **Lavalink v4**
45
+ - Built with **TypeScript** with **ES Modules** and **CommonJS** support
46
+ - Multiple Discord library wrappers available
47
+ - Follows the **Lavalink API** closely and provides a consistent way to interact with Lavalink
48
+
49
+ # Installation
50
+
51
+ Install Lavacord using either `yarn`, `npm`, `pnpm` or the package manager of your choice:
15
52
 
16
- **For stable**
17
53
  ```bash
18
54
  # Using yarn
19
55
  yarn add lavacord
20
-
21
56
  # Using npm
22
57
  npm install lavacord
58
+ # Using pnpm
59
+ pnpm add lavacord
23
60
  ```
24
61
 
25
- **For Development**
26
- ```bash
27
- # Using yarn
28
- yarn add lavacord/lavacord
62
+ **Requirements:**
29
63
 
30
- # Using npm
31
- npm install lavacord/lavacord
32
- ```
64
+ - **Node.js** v20 or newer is **required**.
65
+ - A running **Lavalink** server (Java 17+ required).
33
66
 
34
- ## LavaLink configuration
35
- Download Lavalink from [their GitHub releases](https://github.com/lavalink-devs/Lavalink/releases)
67
+ # Quick Start
36
68
 
37
- Put an `application.yml` file in your working directory. [Example](https://github.com/lavalink-devs/Lavalink/blob/master/LavalinkServer/application.yml.example)
69
+ To get started with using Lavacord, first ensure you have a Lavalink server running. You can find instructions on how to set up a Lavalink server on the [Lavalink Getting Started page](https://lavalink.dev/getting-started/).
38
70
 
39
- Run with `java -jar Lavalink.jar`
71
+ Once you have Lavacord installed, you will want to import the `Manager` class from Lavacord or one of the library wrappers, depending on which Discord library you are using, then initialise it with your Lavalink nodes and bot user ID and send function if not using a wrapper.
40
72
 
41
- ## The issue tracker is for issues only
42
- If you're having a problem with the module contact us in the [**Discord Server**](https://discord.gg/wXrjZmV)
73
+ **Also keep in mind that while all the examples below use CommonJS syntax, Lavacord supports TypeScript, ESM, and CJS. You can import the `Manager` class using either `require` or `import` syntax, depending on your project setup.**
43
74
 
44
- # Implementation
45
- Start by creating a new `Manager` passing an array of nodes and an object with `user` the client's user id.
75
+ ## Lavalink Node Configuration
46
76
 
47
- ```javascript
48
- // import the Manager class from lavacord
49
- const { Manager } = require("lavacord");
77
+ To connect to a Lavalink server, you need to configure the Lavalink nodes. Each node should have a unique identifier, host, port, password, and an optional secure flag if using SSL/TLS.
78
+
79
+ We are going to use this node's array throughout all the examples in this readme, so make sure to define it before using the examples.
80
+
81
+ See [LavalinkNodeOptions](https://lavacord.js.org/interfaces/LavalinkNodeOptions.html) for more details on the available options.
82
+
83
+ You can define your Lavalink nodes in an array like this:
50
84
 
51
- // Define the nodes array as an example
85
+ ```javascript
52
86
  const nodes = [
53
- { id: "1", host: "localhost", port: 2333, password: "youshallnotpass" }
87
+ {
88
+ id: "node1", // Unique identifier for the node
89
+ host: "localhost", // Lavalink server host
90
+ port: 2333, // Lavalink server port
91
+ password: "youshallnotpass", // Lavalink server password
92
+ secure: false, // Set to true if using SSL/TLS, false by default,
93
+ reconnectInterval: 10000, // How long the interval should be to reconnect, default is 10000 ms
94
+ state: {
95
+ // State is a arbitrary object that can be used to store any data you want, it is not used by Lavacord nor do you have to use it
96
+ customData: "example" // Example custom data
97
+ }
98
+ }
54
99
  ];
100
+ ```
101
+
102
+ ## Supported Discord Libraries
103
+
104
+ Lavacord provides wrappers for popular Discord libraries:
105
+
106
+ Each wrapper automatically wires up voice events and exports a `Manager` class tailored for that library.
107
+
108
+ | Library | Import Path |
109
+ | ---------- | --------------------- |
110
+ | discord.js | `lavacord/discord.js` |
111
+ | eris | `lavacord/eris` |
112
+ | oceanic.js | `lavacord/oceanic` |
113
+ | cloudstorm | `lavacord/cloudstorm` |
114
+ | detritus | `lavacord/detritus` |
115
+
116
+ > Want support for another Discord API library?
117
+ > [Open an issue or discussion](https://github.com/lavacord/lavacord/issues) to suggest it!
118
+
119
+ ## Wrapper Example
120
+
121
+ Here's how to use Lavacord with the `discord.js` library wrapper:
122
+
123
+ ```javascript
124
+ const { Manager } = require("lavacord/discord.js");
125
+ const { Client, GatewayIntentBits } = require("discord.js");
126
+
127
+ const client = new Client({
128
+ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates]
129
+ });
130
+
131
+ // When using library wrappers, pass the client instance as the first parameter
132
+ const manager = new Manager(client, nodes);
133
+
134
+ client.once("ready", async () => {
135
+ console.log(`${client.user.tag} is ready!`);
136
+ // Connect to all Lavalink nodes
137
+ await manager.connect();
138
+ });
139
+
140
+ client.login("your-bot-token");
141
+ ```
142
+
143
+ Library wrappers automatically handle:
55
144
 
56
- // Initilize the Manager with all the data it needs
145
+ - **Voice events**: Listens for `VOICE_SERVER_UPDATE` and `VOICE_STATE_UPDATE` events
146
+ - **Send function**: Implements the Discord gateway packet sending for you
147
+
148
+ This eliminates the need to manually wire up voice events or implement the send function, making integration much simpler compared to using the core library directly.
149
+
150
+ # Basic Usage
151
+
152
+ Here's a complete example using the core Lavacord library without wrappers:
153
+
154
+ ```javascript
155
+ const { Manager, Rest } = require("lavacord");
156
+
157
+ // Create a new Manager instance with Lavalink nodes
57
158
  const manager = new Manager(nodes, {
58
- user: client.user.id, // Client id
59
- send: (packet) => {
60
- // this needs to send the provided packet to discord's WS using the method from your library.
61
- // use the bindings for the discord library you use if you don't understand this
62
- }
159
+ userId: "123456789012345678", // Your bot's user ID
160
+ send: (packet) => {
161
+ // Send voice packets to Discord's gateway
162
+ // Implementation depends on your Discord library
163
+ // Use library wrappers to avoid implementing this manually
164
+ discordClient.gateway.send(packet);
165
+ }
63
166
  });
64
167
 
65
- // Connects all the LavalinkNode WebSockets
168
+ // Connect to all Lavalink nodes
66
169
  await manager.connect();
67
170
 
68
- // The error event, which you should handle otherwise your application will crash when an error is emitted
69
- manager.on("error", (error, node) => {
70
- error, // is the error
71
- node // is the node which the error is from
171
+ // Join a voice channel and create a player
172
+ const player = await manager.join({
173
+ guild: "987654321098765432", // Guild ID where you want to play music
174
+ channel: "123456789012345678", // Voice channel ID to join
175
+ node: "node1" // Lavalink node ID to use (optional, auto-selects if not provided)
176
+ });
177
+
178
+ // Load a track from various sources
179
+ // see https://lavalink.dev/api/rest.html#track-loading
180
+ const loadResult = await Rest.load(player.node, "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
181
+
182
+ if (loadResult.loadType === "track") {
183
+ // Play the loaded track
184
+ await player.play(loadResult.data.encoded);
185
+ console.log(`Now playing: ${loadResult.data.info.title}`);
186
+ } else if (loadResult.loadType === "playlist") {
187
+ // Play first track from playlist
188
+ const firstTrack = loadResult.data.tracks[0];
189
+ await player.play(firstTrack.encoded);
190
+ console.log(`Playing playlist: ${loadResult.data.info.name}`);
191
+ } else if (loadResult.loadType === "search") {
192
+ // Play first search result
193
+ if (loadResult.data.length > 0) {
194
+ await player.play(loadResult.data[0].encoded);
195
+ console.log(`Now playing: ${loadResult.data[0].info.title}`);
196
+ } else {
197
+ console.log("No search results found");
198
+ }
199
+ } else {
200
+ console.log("No tracks found");
201
+ }
202
+
203
+ // Listen for when tracks start playing
204
+ player.on("trackStart", (track) => {
205
+ console.log(`Started playing: ${track.info.title}`);
206
+ });
207
+
208
+ // Listen for when tracks end
209
+ player.on("trackEnd", (track, reason) => {
210
+ console.log(`Track ended: ${track.info.title} (${reason})`);
72
211
  });
73
212
  ```
74
213
 
75
- Resolving tracks using LavaLink REST API
214
+ ## Search Examples
215
+
216
+ You can also search for tracks instead of using direct URLs:
217
+ See [Track Loading](https://lavalink.dev/api/rest.html#track-loading) for more information on the loadtracks endpoint.
76
218
 
77
219
  ```javascript
78
- const { Rest } = require("lavacord");
220
+ // Search YouTube
221
+ const searchResult = await Rest.load(player.node, "ytsearch:Never Gonna Give You Up");
222
+
223
+ // Search SoundCloud
224
+ const scResult = await Rest.load(player.node, "scsearch:lofi hip hop");
79
225
 
80
- async function getSongs(search) {
81
- // This gets the best node available, what I mean by that is the idealNodes getter will filter all the connected nodes and then sort them from best to least beast.
82
- const node = manager.idealNodes[0];
226
+ // Search Spotify (if enabled on Lavalink server)
227
+ const spotifyResult = await Rest.load(player.node, "spsearch:bohemian rhapsody");
83
228
 
84
- return Rest.load(node, search)
85
- .catch(err => {
86
- console.error(err);
87
- return null;
88
- });
229
+ if (searchResult.loadType === "search") {
230
+ if (searchResult.data.length > 0) {
231
+ await player.play(searchResult.data[0].encoded); // Play first result
232
+ }
89
233
  }
234
+ ```
235
+
236
+ # Advanced Usage
90
237
 
91
- getSongs("ytsearch:30 second song").then(songs => {
92
- // handle loading of the tracks somehow ¯\_(ツ)_/¯
238
+ ## Player Controls
239
+
240
+ ```javascript
241
+ // Basic playback controls
242
+ await player.pause(true); // Pause
243
+ await player.pause(false); // Resume
244
+ await player.stop(); // Stop current track
245
+ await player.seek(30000); // Seek to 30 seconds
246
+ await player.setVolume(50); // Set volume to 50% (0-1000 range)
247
+
248
+ // All of these helpers call player.update(UpdatePlayerData), each of which returns a Promise<UpdatePlayerResult>
249
+ // You can see more here https://lavalink.dev/api/rest.html#update-player
250
+ // For example to set the volume using player.update:
251
+ await player.update({
252
+ volume: 50 // Set volume to 50%
93
253
  });
94
254
  ```
95
255
 
96
- Joining and Leaving channels
256
+ ## Audio Filters
257
+
258
+ Lavacord supports Lavalink's audio filters for sound enhancement:
97
259
 
98
260
  ```javascript
99
- // Join
100
- const player = await manager.join({
101
- guild: guildId, // Guild id
102
- channel: channelId, // Channel id
103
- node: "1" // lavalink node id, based on array of nodes
261
+ // Apply equalizer (15-band, -0.25 to 1.0 gain per band)
262
+ await player.setEqualizer([
263
+ { band: 0, gain: 0.2 }, // 25 Hz
264
+ { band: 1, gain: 0.15 }, // 40 Hz
265
+ { band: 2, gain: 0.1 } // 63 Hz
266
+ // ... up to band 14 (16 kHz)
267
+ ]);
268
+
269
+ // Apply multiple filters at once
270
+ await player.setFilters({
271
+ timescale: {
272
+ speed: 1.2, // 20% faster
273
+ pitch: 1.0, // Same pitch
274
+ rate: 1.0 // Same rate
275
+ },
276
+ karaoke: {
277
+ level: 1.0,
278
+ monoLevel: 1.0,
279
+ filterBand: 220.0,
280
+ filterWidth: 100.0
281
+ },
282
+ tremolo: {
283
+ frequency: 2.0,
284
+ depth: 0.5
285
+ }
286
+ });
287
+
288
+ // Clear all filters
289
+ await player.setFilters({});
290
+ ```
291
+
292
+ ## Error Handling
293
+
294
+ ```javascript
295
+ // Handle player errors
296
+ player.on("trackException", (track, exception) => {
297
+ console.error(`Track failed: ${track.info.title}`, exception);
298
+ });
299
+
300
+ player.on("trackStuck", (track, thresholdMs) => {
301
+ console.error(`Track stuck: ${track.info.title} (${thresholdMs}ms)`);
302
+ });
303
+
304
+ // Handle node errors
305
+ manager.on("error", (error, node) => {
306
+ console.error(`Node ${node.id} error:`, error);
307
+ });
308
+
309
+ manager.on("disconnect", (code, reason, node) => {
310
+ console.warn(`Node ${node.id} disconnected: ${reason} (${code})`);
311
+ // Players will automatically switch to other available nodes
312
+ });
313
+ ```
314
+
315
+ ## Multiple Nodes & Load Balancing
316
+
317
+ ```javascript
318
+ const nodes = [
319
+ {
320
+ id: "node1",
321
+ host: "lavalink1.example.com",
322
+ port: 2333,
323
+ password: "youshallnotpass"
324
+ },
325
+ {
326
+ id: "node2",
327
+ host: "lavalink2.example.com",
328
+ port: 2333,
329
+ password: "youshallnotpass"
330
+ }
331
+ ];
332
+
333
+ const manager = new Manager(nodes, options);
334
+
335
+ // Lavacord automatically selects the best node based on CPU load
336
+ const player = await manager.join({ guild: "...", channel: "...", node: "node1" });
337
+ console.log(`Using node: ${player.node.id}`);
338
+
339
+ // Manually switch a player to a different node
340
+ const targetNode = manager.nodes.get("node2");
341
+ await manager.switch(player, targetNode);
342
+ ```
343
+
344
+ # Events
345
+
346
+ Lavacord emits events at both the `Manager` and `Player` levels, allowing you to handle events globally or per-player. Player events emitted on the `Manager` are prefixed with `player` to avoid conflicts.
347
+
348
+ ## Manager Events
349
+
350
+ ```javascript
351
+ // Fired when a node successfully connects
352
+ manager.on("ready", (node) => {
353
+ console.log(`Node ${node.id} is ready`);
354
+ });
355
+
356
+ // Fired when a node encounters an error
357
+ manager.on("error", (error, node) => {
358
+ console.error(`Node ${node.id} error:`, error);
359
+ });
360
+
361
+ // Fired when a node disconnects
362
+ manager.on("disconnect", (code, reason, node) => {
363
+ console.log(`Node ${node.id} disconnected: ${reason} (Code: ${code})`);
364
+ });
365
+
366
+ // Fired when a node is attempting to reconnect
367
+ manager.on("reconnecting", (node) => {
368
+ console.log(`Reconnecting to node ${node.id}`);
369
+ });
370
+
371
+ // Fired for raw WebSocket messages (useful for debugging)
372
+ manager.on("raw", (message, node) => {
373
+ console.log(`Raw data from ${node.id}:`, message);
374
+ });
375
+
376
+ // Fired for warning messages
377
+ manager.on("warn", (message, node) => {
378
+ console.warn(`Warning from ${node.id}: ${message}`);
379
+ });
380
+ ```
381
+
382
+ ### Player Events on Manager
383
+
384
+ ```javascript
385
+ // Track events
386
+
387
+ // https://lavalink.dev/api/websocket.html#trackstartevent
388
+ manager.on("playerTrackStart", (player, event) => {
389
+ console.log(`Player ${player.guildId} started: ${event.track.info.title}`);
390
+ });
391
+
392
+ // https://lavalink.dev/api/websocket.html#trackendevent
393
+ manager.on("playerTrackEnd", (player, event) => {
394
+ console.log(`Player ${player.guildId} ended: ${event.track.info.title} (${event.reason})`);
395
+ });
396
+
397
+ // https://lavalink.dev/api/websocket.html#trackexceptionevent
398
+ manager.on("playerTrackException", (player, event) => {
399
+ console.error(`Player ${player.guildId} exception:`, event.exception);
400
+ });
401
+
402
+ // https://lavalink.dev/api/websocket.html#trackstuckevent
403
+ // Fired when a track is stuck (e.g., no audio received for a long time)
404
+ manager.on("playerTrackStuck", (player, event) => {
405
+ console.error(`Player ${player.guildId} stuck: ${event.thresholdMs}ms`);
406
+ });
407
+
408
+ // playerState will emit every x time specified in the Lavalink config
409
+ // See https://lavalink.dev/api/websocket.html#player-update-op
410
+ manager.on("playerState", (player, state) => {
411
+ console.log(`Player ${player.guildId} state update:`, state);
104
412
  });
105
413
 
106
- await player.play(track); // Track is a base64 string we get from Lavalink REST API
414
+ // https://lavalink.dev/api/websocket.html#websocketclosedevent
415
+ manager.on("playerWebSocketClosed", (player, event) => {
416
+ console.log(`Player ${player.guildId} WebSocket closed: ${event.reason} (${event.code}) by ${event.byRemote ? "discord" : "local"}`);
417
+ });
418
+
419
+ // These events aren’t part of the Lavalink API; they are emitted by Lavacord when you invoke specific methods
420
+
421
+ // for example pause is emitted when calling player.pause(true) or player.pause(false);
422
+ manager.on("playerPause", (player, state) => {
423
+ console.log(`Player ${player.guildId} pause: ${state}`);
424
+ });
425
+
426
+ manager.on("playerVolume", (player, volume) => {
427
+ console.log(`Player ${player.guildId} volume: ${volume}`);
428
+ });
429
+
430
+ manager.on("playerSeek", (player, position) => {
431
+ console.log(`Player ${player.guildId} seek: ${position}ms`);
432
+ });
433
+
434
+ manager.on("playerFilters", (player, filters) => {
435
+ console.log(`Player ${player.guildId} filters:`, filters);
436
+ });
437
+ ```
438
+
439
+ ## Player Events
440
+
441
+ Handle events on individual player instances:
442
+
443
+ ```javascript
444
+ // Track events - fired when tracks start, end, or encounter issues
445
+
446
+ // https://lavalink.dev/api/websocket.html#trackstartevent
447
+ player.on("trackStart", (event) => {
448
+ console.log(`Now playing: ${event.track.info.title} by ${event.track.info.author}`);
449
+ });
450
+
451
+ // https://lavalink.dev/api/websocket.html#trackendevent
452
+ player.on("trackEnd", (event) => {
453
+ console.log(`Track ended: ${event.track.info.title} (${event.reason})`);
454
+ // Reasons: "finished", "loadFailed", "stopped", "replaced", "cleanup"
455
+ });
456
+ // https://lavalink.dev/api/websocket.html#trackexceptionevent
457
+ player.on("trackException", (event) => {
458
+ console.error(`Track exception: ${event.track.info.title}`, event.exception);
459
+ });
107
460
 
108
- player.once("error", error => console.error(error));
109
- player.once("end", data => {
110
- if (data.type === "TrackEndEvent" && data.reason === "replaced") return; // Ignore replaced reason to prevent skip loops
111
- // Play next song
461
+ // https://lavalink.dev/api/websocket.html#trackstuckevent
462
+ // Fired when a track is stuck (e.g., no audio received for a long time)
463
+ player.on("trackStuck", (event) => {
464
+ console.error(`Track stuck: ${event.track.info.title} (${event.thresholdMs}ms)`);
112
465
  });
113
466
 
114
- // Leave voice channel and destroy Player
115
- await manager.leave(guildId); // Player ID aka guild id
467
+ // state will emit every x time specified in the Lavalink config
468
+ // See https://lavalink.dev/api/websocket.html#player-update-op
469
+ player.on("state", (state) => {
470
+ console.log(`Player state:`, {
471
+ position: state.position,
472
+ time: state.time,
473
+ connected: state.connected,
474
+ ping: state.ping
475
+ });
476
+ });
477
+
478
+ // https://lavalink.dev/api/websocket.html#websocketclosedevent
479
+ player.on("webSocketClosed", (event) => {
480
+ console.log(`WebSocket closed: ${event.reason} (${event.code}) by ${event.byRemote ? "discord" : "local"}`);
481
+ });
482
+
483
+ // These events aren’t part of the Lavalink API; they are emitted by Lavacord when you invoke specific methods
484
+
485
+ // for example pause is emitted when calling player.pause(true) or player.pause(false);
486
+ player.on("pause", (state) => {
487
+ console.log(`Player ${state ? "paused" : "resumed"}`);
488
+ });
489
+
490
+ player.on("volume", (volume) => {
491
+ console.log(`Volume changed to: ${volume}`);
492
+ });
493
+
494
+ player.on("seek", (position) => {
495
+ console.log(`Seeked to: ${position}ms`);
496
+ });
497
+
498
+ player.on("filters", (filters) => {
499
+ console.log(`Filters applied:`, filters);
500
+ });
116
501
  ```
502
+
503
+ # Donate
504
+
505
+ If you find Lavacord useful and want to support its development, you can sponsor the main maintainers directly:
506
+
507
+ - [MrJacz](https://github.com/sponsors/MrJacz)
508
+ - [AmandaDiscord](https://github.com/sponsors/AmandaDiscord)
509
+
510
+ Thank you for your support!
511
+
512
+ # Contributors
513
+
514
+ Please make sure to read the [Contributing Guide](CONTRIBUTING.md) before making a pull request.
515
+
516
+ Thank you to everyone who has contributed to Lavacord!
517
+
518
+ <a href="https://github.com/lavacord/Lavacord/graphs/contributors">
519
+ <img src="https://contrib.rocks/image?repo=lavacord/Lavacord" alt="Contributors to Lavacord" />
520
+ </a>
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ var LavalinkNode_cjs = require('./lib/LavalinkNode.cjs');
4
+ var Player_cjs = require('./lib/Player.cjs');
5
+ var Manager_cjs = require('./lib/Manager.cjs');
6
+ var Rest_cjs = require('./lib/Rest.cjs');
7
+ var Types_cjs = require('./lib/Types.cjs');
8
+
9
+ // src/index.ts
10
+ var VERSION = "3.0.0";
11
+
12
+ exports.VERSION = VERSION;
13
+ Object.keys(LavalinkNode_cjs).forEach(function (k) {
14
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
15
+ enumerable: true,
16
+ get: function () { return LavalinkNode_cjs[k]; }
17
+ });
18
+ });
19
+ Object.keys(Player_cjs).forEach(function (k) {
20
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
21
+ enumerable: true,
22
+ get: function () { return Player_cjs[k]; }
23
+ });
24
+ });
25
+ Object.keys(Manager_cjs).forEach(function (k) {
26
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
27
+ enumerable: true,
28
+ get: function () { return Manager_cjs[k]; }
29
+ });
30
+ });
31
+ Object.keys(Rest_cjs).forEach(function (k) {
32
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
33
+ enumerable: true,
34
+ get: function () { return Rest_cjs[k]; }
35
+ });
36
+ });
37
+ Object.keys(Types_cjs).forEach(function (k) {
38
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
39
+ enumerable: true,
40
+ get: function () { return Types_cjs[k]; }
41
+ });
42
+ });
43
+ //# sourceMappingURL=index.cjs.map
44
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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.0\";\n"]}