lavalink-client 1.0.4 → 1.0.5

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 (32) hide show
  1. package/README.md +32 -98
  2. package/dist/cjs/structures/LavalinkManager.d.ts +16 -14
  3. package/dist/cjs/structures/LavalinkManager.js +3 -14
  4. package/dist/cjs/structures/Node.js +10 -7
  5. package/dist/cjs/structures/NodeManager.d.ts +1 -12
  6. package/dist/cjs/structures/NodeManager.js +53 -60
  7. package/dist/cjs/structures/Player.d.ts +4 -4
  8. package/dist/cjs/structures/Player.js +20 -7
  9. package/dist/cjs/structures/Queue.d.ts +9 -9
  10. package/dist/cjs/structures/Queue.js +24 -23
  11. package/dist/cjs/structures/Track.d.ts +14 -3
  12. package/dist/cjs/structures/Utils.d.ts +20 -5
  13. package/dist/cjs/structures/Utils.js +81 -13
  14. package/dist/esm/structures/LavalinkManager.d.ts +16 -14
  15. package/dist/esm/structures/LavalinkManager.js +3 -14
  16. package/dist/esm/structures/Node.js +10 -7
  17. package/dist/esm/structures/NodeManager.d.ts +1 -12
  18. package/dist/esm/structures/NodeManager.js +53 -60
  19. package/dist/esm/structures/Player.d.ts +4 -4
  20. package/dist/esm/structures/Player.js +20 -7
  21. package/dist/esm/structures/Queue.d.ts +9 -9
  22. package/dist/esm/structures/Queue.js +25 -24
  23. package/dist/esm/structures/Track.d.ts +14 -3
  24. package/dist/esm/structures/Utils.d.ts +20 -5
  25. package/dist/esm/structures/Utils.js +81 -13
  26. package/dist/types/structures/LavalinkManager.d.ts +16 -14
  27. package/dist/types/structures/NodeManager.d.ts +1 -12
  28. package/dist/types/structures/Player.d.ts +4 -4
  29. package/dist/types/structures/Queue.d.ts +9 -9
  30. package/dist/types/structures/Track.d.ts +14 -3
  31. package/dist/types/structures/Utils.d.ts +20 -5
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -1,17 +1,42 @@
1
- # lavalink-client
2
- Easy and advanced lavalink client. Use it with lavalink plugins as well as latest lavalink versions
1
+ # Lavalink Client
2
+ Easy and advanced lavalink client. Use it with lavalink plugins as well as latest lavalink versions.
3
3
 
4
4
  # Install
5
5
 
6
6
  Latest stable Version: (currently, unreleased)
7
- ```
7
+
8
+ <details><summary>👉 via NPM</summary>
9
+
10
+ ```bash
8
11
  npm install --save lavalink-client
9
12
  ```
13
+
10
14
  Dev Version: (Current)
11
- ```
15
+
16
+ ```bash
12
17
  npm install tomato6966/lavalink-client
13
18
  ```
14
19
 
20
+ </details>
21
+
22
+ <details><summary>👉 via YARN</summary>
23
+
24
+ ```bash
25
+ yarn add lavalink-client
26
+ ```
27
+
28
+ Dev Version: (Current)
29
+
30
+ ```bash
31
+ yarn add tomato6966/lavalink-client
32
+ ```
33
+
34
+ </details>
35
+
36
+ # Documentation
37
+
38
+ Check out the [Documentation](https://lc4.gitbook.io/lavalink-client) for **Examples**, and **__detailled__ Docs**, and to figure out **how to get started**. *note: it's not fully done yet (see the docs)*
39
+
15
40
  # Features
16
41
 
17
42
  - 💯 Lavalink v4 Supported only (with Lavalink Plugins)
@@ -21,6 +46,8 @@ npm install tomato6966/lavalink-client
21
46
 
22
47
  - ✨ Choose able queue stores (maps, collections, redis, databases, ...)
23
48
  - You can create your own queueStore, thus make it easy to sync queues accross multiple connections (e.g. dashboard-bot)
49
+ - Automated Queue Sync methods
50
+ - Automated unresolveable Tracks (save the queries as Partial Track Objects -> Fetch the tracks only once they are gonna play)
24
51
 
25
52
  - 😍 Included Filter & Equalizer Management
26
53
 
@@ -41,98 +68,5 @@ npm install tomato6966/lavalink-client
41
68
  - Destroys the player on channeldelete
42
69
  - Pauses / resumes the player if it get's muted / unmuted (server-wide) [soon]
43
70
  - ...
44
- - 😁 Much much more!
45
-
46
- # Documentation
47
-
48
- *soon*
49
-
50
- # How to Use
51
-
52
- 1. Import the Manager
53
-
54
- ```ts
55
- import { LavalinkManager } from "lavalink-client"; // Modular JS / Typescript
56
- ```
57
-
58
- ```js
59
- const { LavalinkManager } = require("lavalink-client"); // Common Js
60
- ```
61
-
62
- 2. create the Manager
63
-
64
- ```ts
65
- // Suggest it to extend it to the bot Client
66
- client.lavalink = new LavalinkManager({
67
- nodes: [
68
- {
69
- authorization: "youshallnotpass",
70
- host: "localhost",
71
- port: 2333,
72
- id: "testnode",
73
- requestTimeout: 10000,
74
- }
75
- ],
76
- sendToShard: (guildId, payload) => client.guilds.cache.get(guildId)?.shard?.send(payload),
77
- autoSkip: true,
78
- client: {
79
- id: envConfig.clientId,
80
- username: "TESTBOT",
81
- shards: "auto"
82
- },
83
- playerOptions: {
84
- applyVolumeAsFilter: false,
85
- clientBasedUpdateInterval: 50,
86
- defaultSearchPlatform: "dzsearch",
87
- volumeDecrementer: 0.7
88
- },
89
- queueOptions: {
90
- maxPreviousTracks: 5
91
- },
92
- // queueStore: new myCustomStore(client.redis), // OPTIONAL! 'class myCustomStore extends DefaultQueueStore' --> for custom queue stores, e.g. redis, etc. | default is lavalink-client#MiniMap
93
- // queueChangesWatcher: new myCustomWatcher(), // OPTIONAL! 'class myCustomWatcher extends QueueChangesWatcher' --> for queue action logs!
94
- });
95
- ```
96
-
97
- 3. **VERY IMPORTANT!** - Register Voice State updates + initialize the Manager
98
-
99
- ```ts
100
- client.on("raw", d => client.lavalink.sendRawData(d)); // for voice state updates!
101
- client.on("ready", async () => {
102
- console.log("Discord Bot is ready to be Used!");
103
- // user.id is required, user.shards (not), user.username (not, but recommended for lavalink stats!)
104
- await client.lavalink.init({ ...client.user!, shards: "auto" });
105
- });
106
- ```
107
-
108
- 4. **Use it!**
109
-
110
- ```ts
111
- // create player
112
- const player = await client.lavalink.createPlayer({
113
- guildId: guild.id, voiceChannelId: voice.id, textChannelId: text.id, // in what guild + channel(s)
114
- selfDeaf: true, selfMute: false, volume: 100 // configuration(s)
115
- });
116
- // connect the player to it's vc
117
- await player.connect();
118
-
119
- const res = await player.search({
120
- query: `Elton John`, // source: `soundcloud`,
121
- }, client.user); // search a query (query-search, url search, identifier search, etc.)
122
-
123
- await player.queue.add(res.tracks); // add 1 track, or an array of tracks
124
- await player.play(); // you can provide specific track, or let the manager choose the track from the queue!
125
- ```
126
-
127
- ## Example (typescript)
128
-
129
- Can be found in the [`/testBot`](https://github.com/Tomato6966/lavalink-client/blob/main/testBot/README.md) Directory
130
-
131
- It contains the following features:
132
71
 
133
- - Example Use for `Redis based Queue`
134
- - Example Use for `Queue Changes Watcher Logger`
135
- - Example Use for `Filters`, `Audio Output`, `equalizers`
136
- - How to make an easy, yet advanced `Slash Commands Only Bot`
137
- - `Slim Memory Usage`
138
- - `All lavalink-client events` displayments
72
+ - 😁 Much much more!
@@ -5,13 +5,12 @@ import { QueueSaverOptions } from "./Queue";
5
5
  import { GuildShardPayload, LavalinkSearchPlatform, ManagerUitls, MiniMap, SearchPlatform, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, VoicePacket, VoiceServer, VoiceState, WebSocketClosedEvent } from "./Utils";
6
6
  import { LavalinkNodeOptions } from "./Node";
7
7
  import { DestroyReasonsType, Player, PlayerOptions } from "./Player";
8
- import { Track } from "./Track";
8
+ import { Track, UnresolvedTrack } from "./Track";
9
9
  export interface LavalinkManager {
10
10
  nodeManager: NodeManager;
11
11
  utils: ManagerUitls;
12
12
  }
13
13
  export interface BotClientOptions {
14
- shards?: number | number[] | "auto";
15
14
  id: string;
16
15
  username?: string;
17
16
  /** So users can pass entire objects / classes */
@@ -47,40 +46,38 @@ export interface ManagerOptions {
47
46
  client?: BotClientOptions;
48
47
  playerOptions?: LavalinkPlayerOptions;
49
48
  autoSkip?: boolean;
50
- defaultLeastUsedNodeSortType?: "memory" | "calls" | "players";
51
- defaultLeastLoadNodeSortType?: "cpu" | "memory";
52
49
  /** @async */
53
50
  sendToShard: (guildId: string, payload: GuildShardPayload) => void;
54
51
  }
55
52
  interface LavalinkManagerEvents {
56
53
  /**
57
54
  * Emitted when a Track started playing.
58
- * @event Manager.playerManager#trackStart
55
+ * @event Manager#trackStart
59
56
  */
60
57
  "trackStart": (player: Player, track: Track, payload: TrackStartEvent) => void;
61
58
  /**
62
59
  * Emitted when a Track finished.
63
- * @event Manager.playerManager#trackEnd
60
+ * @event Manager#trackEnd
64
61
  */
65
62
  "trackEnd": (player: Player, track: Track, payload: TrackEndEvent) => void;
66
63
  /**
67
64
  * Emitted when a Track got stuck while playing.
68
- * @event Manager.playerManager#trackStuck
65
+ * @event Manager#trackStuck
69
66
  */
70
67
  "trackStuck": (player: Player, track: Track, payload: TrackStuckEvent) => void;
71
68
  /**
72
69
  * Emitted when a Track errored.
73
- * @event Manager.playerManager#trackError
70
+ * @event Manager#trackError
74
71
  */
75
- "trackError": (player: Player, track: Track, payload: TrackExceptionEvent) => void;
72
+ "trackError": (player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent) => void;
76
73
  /**
77
74
  * Emitted when the Playing finished and no more tracks in the queue.
78
- * @event Manager.playerManager#queueEnd
75
+ * @event Manager#queueEnd
79
76
  */
80
77
  "queueEnd": (player: Player, track: Track, payload: TrackEndEvent | TrackStuckEvent | TrackExceptionEvent) => void;
81
78
  /**
82
79
  * Emitted when a Player is created.
83
- * @event Manager.playerManager#create
80
+ * @event Manager#playerCreate
84
81
  */
85
82
  "playerCreate": (player: Player) => void;
86
83
  /**
@@ -90,19 +87,24 @@ interface LavalinkManagerEvents {
90
87
  "playerMove": (player: Player, oldVoiceChannelId: string, newVoiceChannelId: string) => void;
91
88
  /**
92
89
  * Emitted when a Player is disconnected from a channel.
93
- * @event Manager.playerManager#disconnect
90
+ * @event Manager#playerDisconnect
94
91
  */
95
92
  "playerDisconnect": (player: Player, voiceChannelId: string) => void;
96
93
  /**
97
94
  * Emitted when a Node-Socket got closed for a specific Player.
98
- * @event Manager.playerManager#socketClosed
95
+ * @event Manager#playerSocketClosed
99
96
  */
100
97
  "playerSocketClosed": (player: Player, payload: WebSocketClosedEvent) => void;
101
98
  /**
102
99
  * Emitted when a Player get's destroyed
103
- * @event Manager.playerManager#destroy
100
+ * @event Manager#playerDestroy
104
101
  */
105
102
  "playerDestroy": (player: Player, destroyReason?: DestroyReasonsType) => void;
103
+ /**
104
+ * Always emits when the player (on lavalink side) got updated
105
+ * @event Manager#playerUpdate
106
+ */
107
+ "playerUpdate": (player: Player) => void;
106
108
  }
107
109
  export interface LavalinkManager {
108
110
  options: ManagerOptions;
@@ -45,10 +45,6 @@ class LavalinkManager extends events_1.EventEmitter {
45
45
  };
46
46
  if (!this.options.autoSkip)
47
47
  this.options.autoSkip = true;
48
- if (!this.options.defaultLeastLoadNodeSortType)
49
- this.options.defaultLeastLoadNodeSortType = "memory";
50
- if (!this.options.defaultLeastUsedNodeSortType)
51
- this.options.defaultLeastUsedNodeSortType = "players";
52
48
  if (!this.options.playerOptions.defaultSearchPlatform)
53
49
  this.options.playerOptions.defaultSearchPlatform = "ytsearch";
54
50
  // default queue options
@@ -66,13 +62,9 @@ class LavalinkManager extends events_1.EventEmitter {
66
62
  if (typeof options.sendToShard !== "function")
67
63
  throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
68
64
  // only check in .init()
69
- // if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string, shards?: 'auto'|number } was not provided, which is required");
65
+ // if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string } was not provided, which is required");
70
66
  if (options.autoSkip && typeof options.autoSkip !== "boolean")
71
67
  throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
72
- if (options.defaultLeastLoadNodeSortType && !["memory", "cpu"].includes(options.defaultLeastLoadNodeSortType))
73
- throw new SyntaxError("ManagerOption.defaultLeastLoadNodeSortType must be 'memory' | 'cpu'");
74
- if (options.defaultLeastUsedNodeSortType && !["memory", "players", "calls"].includes(options.defaultLeastUsedNodeSortType))
75
- throw new SyntaxError("ManagerOption.defaultLeastLoadNodeSortType must be 'memory' | 'calls' | 'players'");
76
68
  if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
77
69
  throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
78
70
  /* QUEUE STORE */
@@ -157,9 +149,7 @@ class LavalinkManager extends events_1.EventEmitter {
157
149
  * @param data
158
150
  */
159
151
  async sendRawData(data) {
160
- if (!this.initiated)
161
- return;
162
- if (!("t" in data))
152
+ if (!this.initiated || !("t" in data))
163
153
  return;
164
154
  // for channel Delete
165
155
  if ("CHANNEL_DELETE" === data.t) {
@@ -167,9 +157,8 @@ class LavalinkManager extends events_1.EventEmitter {
167
157
  if (!update.guild_id)
168
158
  return;
169
159
  const player = this.getPlayer(update.guild_id);
170
- if (player.voiceChannelId === update.id) {
160
+ if (player && player.voiceChannelId === update.id)
171
161
  return player.destroy(Player_1.DestroyReasons.ChannelDeleted);
172
- }
173
162
  }
174
163
  // for voice updates
175
164
  if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
@@ -137,9 +137,8 @@ class LavalinkNode {
137
137
  return;
138
138
  const headers = {
139
139
  Authorization: this.options.authorization,
140
- "Num-Shards": String(this.NodeManager.LavalinkManager.options.client.shards || "auto"),
141
140
  "User-Id": this.NodeManager.LavalinkManager.options.client.id,
142
- "User-Name": this.NodeManager.LavalinkManager.options.client.username || "Lavalink-Client",
141
+ "Client-Name": this.NodeManager.LavalinkManager.options.client.username || "Lavalink-Client",
143
142
  };
144
143
  if (typeof this.options.sessionId === "string" || typeof sessionId === "string") {
145
144
  headers["Session-Id"] = this.options.sessionId || sessionId;
@@ -477,6 +476,7 @@ class LavalinkNode {
477
476
  player.filterManager.filterUpdatedState = 0;
478
477
  }
479
478
  }
479
+ this.NodeManager.LavalinkManager.emit("playerUpdate", player);
480
480
  break;
481
481
  case "event":
482
482
  this.handleEvent(payload);
@@ -523,6 +523,7 @@ class LavalinkNode {
523
523
  return this.NodeManager.LavalinkManager.emit("trackStart", player, track, payload);
524
524
  }
525
525
  async trackEnd(player, track, payload) {
526
+ console.log(payload.reason);
526
527
  // If there are no songs in the queue
527
528
  if (!player.queue.tracks.length && player.repeatMode === "off")
528
529
  return this.queueEnd(player, track, payload);
@@ -531,7 +532,7 @@ class LavalinkNode {
531
532
  return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
532
533
  // If a track had an error while starting
533
534
  if (["loadFailed", "cleanup"].includes(payload.reason)) {
534
- await (0, Utils_1.queueTrackEnd)(player.queue, false);
535
+ await (0, Utils_1.queueTrackEnd)(player);
535
536
  // if no track available, end queue
536
537
  if (!player.queue.current)
537
538
  return this.queueEnd(player, track, payload);
@@ -542,7 +543,7 @@ class LavalinkNode {
542
543
  }
543
544
  // remove tracks from the queue
544
545
  if (player.repeatMode !== "track")
545
- await (0, Utils_1.queueTrackEnd)(player.queue, player.repeatMode === "queue");
546
+ await (0, Utils_1.queueTrackEnd)(player);
546
547
  // if no track available, end queue
547
548
  if (!player.queue.current)
548
549
  return this.queueEnd(player, track, payload);
@@ -552,15 +553,17 @@ class LavalinkNode {
552
553
  return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
553
554
  }
554
555
  async queueEnd(player, track, payload) {
556
+ // add previous track to the queue!
555
557
  player.queue.current = null;
556
558
  player.playing = false;
557
559
  if (typeof this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function") {
558
560
  await this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track);
559
561
  if (player.queue.tracks.length > 0)
560
- await (0, Utils_1.queueTrackEnd)(player.queue, player.repeatMode === "queue");
562
+ await (0, Utils_1.queueTrackEnd)(player);
561
563
  if (player.queue.current)
562
564
  return player.play({ noReplace: true, paused: false });
563
565
  }
566
+ player.queue.previous.unshift(track);
564
567
  if (payload?.reason !== "stopped") {
565
568
  await player.queue.utils.save();
566
569
  }
@@ -585,7 +588,7 @@ class LavalinkNode {
585
588
  if (!player.queue.tracks.length && player.repeatMode === "off")
586
589
  return;
587
590
  // remove the current track, and enqueue the next one
588
- await (0, Utils_1.queueTrackEnd)(player.queue, player.repeatMode === "queue");
591
+ await (0, Utils_1.queueTrackEnd)(player);
589
592
  // if no track available, end queue
590
593
  if (!player.queue.current)
591
594
  return this.queueEnd(player, track, payload);
@@ -595,7 +598,7 @@ class LavalinkNode {
595
598
  async trackError(player, track, payload) {
596
599
  this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
597
600
  // remove the current track, and enqueue the next one
598
- await (0, Utils_1.queueTrackEnd)(player.queue, player.repeatMode === "queue");
601
+ await (0, Utils_1.queueTrackEnd)(player);
599
602
  // if no track available, end queue
600
603
  if (!player.queue.current)
601
604
  return this.queueEnd(player, track, payload);
@@ -55,18 +55,7 @@ export declare class NodeManager extends EventEmitter {
55
55
  nodes: MiniMap<string, LavalinkNode>;
56
56
  constructor(LavalinkManager: LavalinkManager);
57
57
  createNode(options: LavalinkNodeOptions): LavalinkNode;
58
- get leastUsedNodes(): LavalinkNode[];
59
- /** Returns the least used Nodes sorted by amount of calls. */
60
- private get leastUsedNodesCalls();
61
- /** Returns the least used Nodes sorted by amount of players. */
62
- private get leastUsedNodesPlayers();
63
- /** Returns the least used Nodes sorted by amount of memory usage. */
64
- private get leastUsedNodesMemory();
65
- /** Returns the least system load Nodes. */
66
- get leastLoadNodes(): LavalinkNode[];
67
- get leastLoadNodesMemory(): LavalinkNode[];
68
- /** Returns the least system load Nodes. */
69
- get leastLoadNodesCpu(): LavalinkNode[];
58
+ leastUsedNodes(sortType?: "memory" | "cpuLavalink" | "cpuSystem" | "calls" | "playingPlayers" | "players"): LavalinkNode[];
70
59
  deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
71
60
  }
72
61
  export {};
@@ -20,68 +20,61 @@ class NodeManager extends stream_1.EventEmitter {
20
20
  this.nodes.set(newNode.id, newNode);
21
21
  return newNode;
22
22
  }
23
- get leastUsedNodes() {
24
- if (this.LavalinkManager.options.defaultLeastUsedNodeSortType === "memory")
25
- return this.leastUsedNodesMemory;
26
- else if (this.LavalinkManager.options.defaultLeastUsedNodeSortType === "calls")
27
- return this.leastUsedNodesCalls;
28
- else
29
- return this.leastUsedNodesPlayers; // this.options.defaultLeastUsedNodeSortType === "players"
30
- }
31
- /** Returns the least used Nodes sorted by amount of calls. */
32
- get leastUsedNodesCalls() {
33
- return [...this.nodes.values()]
34
- .filter((node) => node.connected)
35
- .sort((a, b) => b.calls - a.calls); // client sided sorting
36
- }
37
- /** Returns the least used Nodes sorted by amount of players. */
38
- get leastUsedNodesPlayers() {
39
- return [...this.nodes.values()]
40
- .filter((node) => node.connected)
41
- .sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
42
- }
43
- /** Returns the least used Nodes sorted by amount of memory usage. */
44
- get leastUsedNodesMemory() {
45
- return [...this.nodes.values()]
46
- .filter((node) => node.connected)
47
- .sort((a, b) => (b.stats?.memory?.used || 0) - (a.stats?.memory?.used || 0)); // sort after memory
48
- }
49
- /** Returns the least system load Nodes. */
50
- get leastLoadNodes() {
51
- if (this.LavalinkManager.options.defaultLeastLoadNodeSortType === "cpu")
52
- return this.leastLoadNodesCpu;
53
- else
54
- return this.leastLoadNodesMemory; // this.options.defaultLeastLoadNodeSortType === "memory"
55
- }
56
- get leastLoadNodesMemory() {
57
- return [...this.nodes.values()]
58
- .filter((node) => node.connected)
59
- .sort((a, b) => {
60
- const aload = a.stats.memory?.used
61
- ? a.stats.memory.used
62
- : 0;
63
- const bload = b.stats.memory?.used
64
- ? b.stats.memory.used
65
- : 0;
66
- return aload - bload;
67
- });
68
- }
69
- /** Returns the least system load Nodes. */
70
- get leastLoadNodesCpu() {
71
- return [...this.nodes.values()]
72
- .filter((node) => node.connected)
73
- .sort((a, b) => {
74
- const aload = a.stats.cpu
75
- ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100
76
- : 0;
77
- const bload = b.stats.cpu
78
- ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100
79
- : 0;
80
- return aload - bload;
81
- });
23
+ leastUsedNodes(sortType = "players") {
24
+ switch (sortType) {
25
+ case "memory":
26
+ {
27
+ return [...this.nodes.values()]
28
+ .filter((node) => node.connected)
29
+ .sort((a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0)); // sort after memor
30
+ }
31
+ break;
32
+ case "cpuLavalink":
33
+ {
34
+ return [...this.nodes.values()]
35
+ .filter((node) => node.connected)
36
+ .sort((a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0)); // sort after memor
37
+ }
38
+ break;
39
+ case "cpuSystem":
40
+ {
41
+ return [...this.nodes.values()]
42
+ .filter((node) => node.connected)
43
+ .sort((a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0)); // sort after memor
44
+ }
45
+ break;
46
+ case "calls":
47
+ {
48
+ return [...this.nodes.values()]
49
+ .filter((node) => node.connected)
50
+ .sort((a, b) => a.calls - b.calls); // client sided sorting
51
+ }
52
+ break;
53
+ case "playingPlayers":
54
+ {
55
+ return [...this.nodes.values()]
56
+ .filter((node) => node.connected)
57
+ .sort((a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0));
58
+ }
59
+ break;
60
+ case "players":
61
+ {
62
+ return [...this.nodes.values()]
63
+ .filter((node) => node.connected)
64
+ .sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
65
+ }
66
+ break;
67
+ default:
68
+ {
69
+ return [...this.nodes.values()]
70
+ .filter((node) => node.connected)
71
+ .sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
72
+ }
73
+ break;
74
+ }
82
75
  }
83
76
  deleteNode(node) {
84
- const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes[0];
77
+ const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes()[0];
85
78
  if (!decodeNode)
86
79
  throw new Error("Node was not found");
87
80
  decodeNode.destroy(Player_1.DestroyReasons.NodeDeleted);
@@ -110,7 +110,7 @@ export declare class Player {
110
110
  * Play the next track from the queue / a specific track, with playoptions for Lavalink
111
111
  * @param options
112
112
  */
113
- play(options?: Partial<PlayOptions>): Promise<void>;
113
+ play(options?: Partial<PlayOptions>): any;
114
114
  /**
115
115
  * Set the Volume for the Player
116
116
  * @param volume The Volume in percent
@@ -143,12 +143,12 @@ export declare class Player {
143
143
  * Set the Repeatmode of the Player
144
144
  * @param repeatMode
145
145
  */
146
- setRepeatMode(repeatMode: RepeatMode): Promise<void>;
146
+ setRepeatMode(repeatMode: RepeatMode): Promise<RepeatMode>;
147
147
  /**
148
148
  * Skip the current song, or a specific amount of songs
149
149
  * @param amount provide the index of the next track to skip to
150
150
  */
151
- skip(skipTo?: number): Promise<true | void>;
151
+ skip(skipTo?: number): Promise<any>;
152
152
  /**
153
153
  * Connects the Player to the Voice Channel
154
154
  * @returns
@@ -172,6 +172,7 @@ export declare class Player {
172
172
  /** Converts the Player including Queue to a Json state */
173
173
  toJSON(): {
174
174
  guildId: string;
175
+ options: PlayerOptions;
175
176
  voiceChannelId: string;
176
177
  textChannelId: string;
177
178
  position: number;
@@ -184,7 +185,6 @@ export declare class Player {
184
185
  createdTimeStamp: number;
185
186
  filters: {};
186
187
  equalizer: import("./Filters").EQBand[];
187
- queue: import("./Queue").StoredQueue;
188
188
  nodeId: string;
189
189
  };
190
190
  }
@@ -67,8 +67,10 @@ class Player {
67
67
  this.voiceChannelId = this.options.voiceChannelId;
68
68
  this.textChannelId = this.options.textChannelId || null;
69
69
  this.node = typeof this.options.node === "string" ? this.LavalinkManager.nodeManager.nodes.get(this.options.node) : this.options.node;
70
- if (!this.node || typeof this.node?.request !== "function")
71
- this.node = this.LavalinkManager.nodeManager.leastUsedNodes.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || this.LavalinkManager.nodeManager.leastUsedNodes[0] || null;
70
+ if (!this.node || typeof this.node.request !== "function") {
71
+ const least = this.LavalinkManager.nodeManager.leastUsedNodes();
72
+ this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
73
+ }
72
74
  if (!this.node)
73
75
  throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
74
76
  if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
@@ -123,10 +125,22 @@ class Player {
123
125
  }
124
126
  if (options?.track && this.LavalinkManager.utils.isTrack(options?.track)) {
125
127
  await this.queue.add(options?.track, 0);
126
- await (0, Utils_1.queueTrackEnd)(this.queue, this.repeatMode === "queue");
128
+ await (0, Utils_1.queueTrackEnd)(this);
127
129
  }
128
130
  if (!this.queue.current && this.queue.tracks.length)
129
- await (0, Utils_1.queueTrackEnd)(this.queue, this.repeatMode === "queue");
131
+ await (0, Utils_1.queueTrackEnd)(this);
132
+ // @ts-ignore
133
+ if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
134
+ try {
135
+ this.queue.current = await this.LavalinkManager.utils.getClosestTrack({ ...(this.queue.current || {}) }, this);
136
+ }
137
+ catch (error) {
138
+ this.LavalinkManager.emit("trackError", this, this.queue.current, error);
139
+ if (this.queue.tracks[0])
140
+ return this.play();
141
+ return;
142
+ }
143
+ }
130
144
  const track = this.queue.current;
131
145
  if (!track)
132
146
  throw new Error(`There is no Track in the Queue, nor provided in the PlayOptions`);
@@ -277,8 +291,7 @@ class Player {
277
291
  async setRepeatMode(repeatMode) {
278
292
  if (!["off", "track", "queue"].includes(repeatMode))
279
293
  throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
280
- this.repeatMode = repeatMode;
281
- return;
294
+ return this.repeatMode = repeatMode;
282
295
  }
283
296
  /**
284
297
  * Skip the current song, or a specific amount of songs
@@ -378,6 +391,7 @@ class Player {
378
391
  toJSON() {
379
392
  return {
380
393
  guildId: this.guildId,
394
+ options: this.options,
381
395
  voiceChannelId: this.voiceChannelId,
382
396
  textChannelId: this.textChannelId,
383
397
  position: this.position,
@@ -390,7 +404,6 @@ class Player {
390
404
  createdTimeStamp: this.createdTimeStamp,
391
405
  filters: this.filterManager?.data || {},
392
406
  equalizer: this.filterManager?.equalizerBands || [],
393
- queue: this.queue?.utils?.getStored?.() || { current: null, tracks: [], previous: [] },
394
407
  nodeId: this.node?.id,
395
408
  };
396
409
  }