lavalink-client 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/structures/LavalinkManager.d.ts +3 -3
- package/dist/cjs/structures/LavalinkManager.js +72 -11
- package/dist/cjs/structures/Node.js +7 -7
- package/dist/cjs/structures/NodeManager.d.ts +11 -0
- package/dist/cjs/structures/NodeManager.js +60 -3
- package/dist/cjs/structures/Player.js +4 -2
- package/dist/cjs/structures/Queue.d.ts +4 -2
- package/dist/cjs/structures/Queue.js +7 -5
- package/dist/cjs/structures/Utils.d.ts +15 -3
- package/dist/cjs/structures/Utils.js +59 -4
- package/dist/esm/structures/LavalinkManager.d.ts +3 -3
- package/dist/esm/structures/LavalinkManager.js +72 -11
- package/dist/esm/structures/Node.js +7 -7
- package/dist/esm/structures/NodeManager.d.ts +11 -0
- package/dist/esm/structures/NodeManager.js +60 -3
- package/dist/esm/structures/Player.js +4 -2
- package/dist/esm/structures/Queue.d.ts +4 -2
- package/dist/esm/structures/Queue.js +7 -5
- package/dist/esm/structures/Utils.d.ts +15 -3
- package/dist/esm/structures/Utils.js +59 -4
- package/dist/types/structures/LavalinkManager.d.ts +3 -3
- package/dist/types/structures/NodeManager.d.ts +11 -0
- package/dist/types/structures/Queue.d.ts +4 -2
- package/dist/types/structures/Utils.d.ts +15 -3
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
|
-
import {
|
|
4
|
+
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";
|
|
@@ -44,11 +44,11 @@ export interface LavalinkPlayerOptions {
|
|
|
44
44
|
export interface ManagerOptions {
|
|
45
45
|
nodes: LavalinkNodeOptions[];
|
|
46
46
|
queueOptions?: QueueSaverOptions;
|
|
47
|
-
queueStore?: StoreManager;
|
|
48
|
-
queueChangesWatcher?: QueueChangesWatcher;
|
|
49
47
|
client?: BotClientOptions;
|
|
50
48
|
playerOptions?: LavalinkPlayerOptions;
|
|
51
49
|
autoSkip?: boolean;
|
|
50
|
+
defaultLeastUsedNodeSortType?: "memory" | "calls" | "players";
|
|
51
|
+
defaultLeastLoadNodeSortType?: "cpu" | "memory";
|
|
52
52
|
/** @async */
|
|
53
53
|
sendToShard: (guildId: string, payload: GuildShardPayload) => void;
|
|
54
54
|
}
|
|
@@ -13,36 +13,97 @@ class LavalinkManager extends events_1.EventEmitter {
|
|
|
13
13
|
initiated = false;
|
|
14
14
|
players = new Utils_1.MiniMap();
|
|
15
15
|
applyDefaultOptions() {
|
|
16
|
+
if (!this.options.playerOptions)
|
|
17
|
+
this.options.playerOptions = {
|
|
18
|
+
applyVolumeAsFilter: false,
|
|
19
|
+
clientBasedPositionUpdateInterval: 100,
|
|
20
|
+
defaultSearchPlatform: "ytsearch",
|
|
21
|
+
onDisconnect: {
|
|
22
|
+
destroyPlayer: true,
|
|
23
|
+
autoReconnect: false
|
|
24
|
+
},
|
|
25
|
+
onEmptyQueue: {
|
|
26
|
+
autoPlayFunction: null,
|
|
27
|
+
destroyAfterMs: undefined
|
|
28
|
+
},
|
|
29
|
+
requesterTransformer: (requester) => {
|
|
30
|
+
// if it's already the transformed requester
|
|
31
|
+
if (typeof requester === "object" && "avatar" in requester && Object.keys(requester).length === 3)
|
|
32
|
+
return requester;
|
|
33
|
+
// if it's still a discord.js User
|
|
34
|
+
if (typeof requester === "object" && "displayAvatarURL" in requester) { // it's a user
|
|
35
|
+
return {
|
|
36
|
+
id: requester.id,
|
|
37
|
+
username: requester.username,
|
|
38
|
+
avatar: requester.displayAvatarURL(),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// if it's non of the above
|
|
42
|
+
return { id: requester.toString(), username: "unknown" }; // reteurn something that makes sense for you!
|
|
43
|
+
},
|
|
44
|
+
volumeDecrementer: 1
|
|
45
|
+
};
|
|
46
|
+
if (!this.options.autoSkip)
|
|
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";
|
|
16
52
|
if (!this.options.playerOptions.defaultSearchPlatform)
|
|
17
53
|
this.options.playerOptions.defaultSearchPlatform = "ytsearch";
|
|
54
|
+
// default queue options
|
|
55
|
+
if (!this.options.queueOptions)
|
|
56
|
+
this.options.queueOptions = {
|
|
57
|
+
maxPreviousTracks: 25,
|
|
58
|
+
queueChangesWatcher: null,
|
|
59
|
+
queueStore: new Queue_1.DefaultQueueStore()
|
|
60
|
+
};
|
|
18
61
|
if (typeof this.options?.queueOptions?.maxPreviousTracks !== "number" || this.options.queueOptions.maxPreviousTracks < 0)
|
|
19
62
|
this.options.queueOptions.maxPreviousTracks = 25;
|
|
20
63
|
return;
|
|
21
64
|
}
|
|
22
65
|
validateAndApply(options) {
|
|
66
|
+
if (typeof options.sendToShard !== "function")
|
|
67
|
+
throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
|
|
68
|
+
// 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");
|
|
70
|
+
if (options.autoSkip && typeof options.autoSkip !== "boolean")
|
|
71
|
+
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
|
+
if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
|
|
77
|
+
throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
|
|
23
78
|
/* QUEUE STORE */
|
|
24
|
-
if (options.queueStore) {
|
|
25
|
-
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueStore));
|
|
79
|
+
if (options.queueOptions?.queueStore) {
|
|
80
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueStore));
|
|
26
81
|
const requiredKeys = ["get", "set", "stringify", "parse", "delete"];
|
|
27
|
-
if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueStore[v] === "function"))
|
|
28
|
-
throw new SyntaxError(`The provided QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
|
|
82
|
+
if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueStore[v] === "function"))
|
|
83
|
+
throw new SyntaxError(`The provided ManagerOption.QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
|
|
29
84
|
}
|
|
30
85
|
else
|
|
31
|
-
this.options.queueStore = new Queue_1.DefaultQueueStore();
|
|
86
|
+
this.options.queueOptions.queueStore = new Queue_1.DefaultQueueStore();
|
|
87
|
+
/* QUEUE WATCHER */
|
|
88
|
+
if (options.queueOptions?.queueChangesWatcher) {
|
|
89
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueChangesWatcher));
|
|
90
|
+
const requiredKeys = ["tracksAdd", "tracksRemoved", "shuffled"];
|
|
91
|
+
if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueChangesWatcher[v] === "function"))
|
|
92
|
+
throw new SyntaxError(`The provided ManagerOption.QueueChangesWatcher, does not have all required functions: ${requiredKeys.join(", ")}`);
|
|
93
|
+
}
|
|
32
94
|
}
|
|
33
95
|
constructor(options) {
|
|
34
96
|
super();
|
|
97
|
+
if (!options)
|
|
98
|
+
throw new SyntaxError("No Manager Options Provided");
|
|
35
99
|
// create options
|
|
36
|
-
this.options =
|
|
37
|
-
|
|
38
|
-
...options
|
|
39
|
-
};
|
|
100
|
+
this.options = options;
|
|
101
|
+
this.utils = new Utils_1.ManagerUitls(this);
|
|
40
102
|
// use the validators
|
|
41
|
-
this.applyDefaultOptions();
|
|
42
103
|
this.validateAndApply(options);
|
|
104
|
+
this.applyDefaultOptions();
|
|
43
105
|
// create classes
|
|
44
106
|
this.nodeManager = new NodeManager_1.NodeManager(this);
|
|
45
|
-
this.utils = new Utils_1.ManagerUitls(this);
|
|
46
107
|
}
|
|
47
108
|
createPlayer(options) {
|
|
48
109
|
if (this.players.has(options.guildId))
|
|
@@ -153,7 +153,7 @@ class LavalinkNode {
|
|
|
153
153
|
}
|
|
154
154
|
/** Get the id of the node */
|
|
155
155
|
get id() {
|
|
156
|
-
return this.options.id || this.options.host
|
|
156
|
+
return this.options.id || `${this.options.host}:${this.options.port}`;
|
|
157
157
|
}
|
|
158
158
|
/**
|
|
159
159
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
@@ -531,14 +531,14 @@ class LavalinkNode {
|
|
|
531
531
|
return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
532
532
|
// If a track had an error while starting
|
|
533
533
|
if (["loadFailed", "cleanup"].includes(payload.reason)) {
|
|
534
|
-
await (0, Utils_1.queueTrackEnd)(player.queue);
|
|
534
|
+
await (0, Utils_1.queueTrackEnd)(player.queue, false);
|
|
535
535
|
// if no track available, end queue
|
|
536
536
|
if (!player.queue.current)
|
|
537
537
|
return this.queueEnd(player, track, payload);
|
|
538
538
|
// fire event
|
|
539
539
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
540
540
|
// play track if autoSkip is true
|
|
541
|
-
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({
|
|
541
|
+
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
542
542
|
}
|
|
543
543
|
// remove tracks from the queue
|
|
544
544
|
if (player.repeatMode !== "track")
|
|
@@ -549,7 +549,7 @@ class LavalinkNode {
|
|
|
549
549
|
// fire event
|
|
550
550
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
551
551
|
// play track if autoSkip is true
|
|
552
|
-
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({
|
|
552
|
+
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
553
553
|
}
|
|
554
554
|
async queueEnd(player, track, payload) {
|
|
555
555
|
player.queue.current = null;
|
|
@@ -559,7 +559,7 @@ class LavalinkNode {
|
|
|
559
559
|
if (player.queue.tracks.length > 0)
|
|
560
560
|
await (0, Utils_1.queueTrackEnd)(player.queue, player.repeatMode === "queue");
|
|
561
561
|
if (player.queue.current)
|
|
562
|
-
return player.play({
|
|
562
|
+
return player.play({ noReplace: true, paused: false });
|
|
563
563
|
}
|
|
564
564
|
if (payload?.reason !== "stopped") {
|
|
565
565
|
await player.queue.utils.save();
|
|
@@ -590,7 +590,7 @@ class LavalinkNode {
|
|
|
590
590
|
if (!player.queue.current)
|
|
591
591
|
return this.queueEnd(player, track, payload);
|
|
592
592
|
// play track if autoSkip is true
|
|
593
|
-
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({
|
|
593
|
+
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
594
594
|
}
|
|
595
595
|
async trackError(player, track, payload) {
|
|
596
596
|
this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
|
|
@@ -600,7 +600,7 @@ class LavalinkNode {
|
|
|
600
600
|
if (!player.queue.current)
|
|
601
601
|
return this.queueEnd(player, track, payload);
|
|
602
602
|
// play track if autoSkip is true
|
|
603
|
-
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({
|
|
603
|
+
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
604
604
|
}
|
|
605
605
|
socketClosed(player, payload) {
|
|
606
606
|
return this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
|
|
@@ -56,6 +56,17 @@ export declare class NodeManager extends EventEmitter {
|
|
|
56
56
|
constructor(LavalinkManager: LavalinkManager);
|
|
57
57
|
createNode(options: LavalinkNodeOptions): LavalinkNode;
|
|
58
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[];
|
|
59
70
|
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
60
71
|
}
|
|
61
72
|
export {};
|
|
@@ -14,14 +14,71 @@ class NodeManager extends stream_1.EventEmitter {
|
|
|
14
14
|
this.LavalinkManager.options.nodes.forEach(node => this.createNode(node));
|
|
15
15
|
}
|
|
16
16
|
createNode(options) {
|
|
17
|
-
if (this.nodes.has(options.id || options.host))
|
|
18
|
-
return this.nodes.get(options.id || options.host);
|
|
17
|
+
if (this.nodes.has(options.id || `${options.host}:${options.port}`))
|
|
18
|
+
return this.nodes.get(options.id || `${options.host}:${options.port}`);
|
|
19
19
|
const newNode = new Node_1.LavalinkNode(options, this);
|
|
20
20
|
this.nodes.set(newNode.id, newNode);
|
|
21
21
|
return newNode;
|
|
22
22
|
}
|
|
23
23
|
get leastUsedNodes() {
|
|
24
|
-
|
|
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
|
+
});
|
|
25
82
|
}
|
|
26
83
|
deleteNode(node) {
|
|
27
84
|
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes[0];
|
|
@@ -66,7 +66,9 @@ class Player {
|
|
|
66
66
|
this.guildId = this.options.guildId;
|
|
67
67
|
this.voiceChannelId = this.options.voiceChannelId;
|
|
68
68
|
this.textChannelId = this.options.textChannelId || null;
|
|
69
|
-
this.node = this.
|
|
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
72
|
if (!this.node)
|
|
71
73
|
throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
|
|
72
74
|
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
@@ -74,7 +76,7 @@ class Player {
|
|
|
74
76
|
this.LavalinkManager.emit("playerCreate", this);
|
|
75
77
|
if (typeof options.volume === "number" && !isNaN(options.volume))
|
|
76
78
|
this.setVolume(options.volume);
|
|
77
|
-
this.queue = new Queue_1.Queue(this.guildId, {}, new Queue_1.QueueSaver(this.LavalinkManager.options.
|
|
79
|
+
this.queue = new Queue_1.Queue(this.guildId, {}, new Queue_1.QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
|
|
78
80
|
}
|
|
79
81
|
/**
|
|
80
82
|
* Set custom data.
|
|
@@ -18,6 +18,8 @@ export interface StoreManager extends Record<any, any> {
|
|
|
18
18
|
}
|
|
19
19
|
export interface QueueSaverOptions {
|
|
20
20
|
maxPreviousTracks: number;
|
|
21
|
+
queueStore?: StoreManager;
|
|
22
|
+
queueChangesWatcher?: QueueChangesWatcher;
|
|
21
23
|
}
|
|
22
24
|
export interface QueueSaver {
|
|
23
25
|
/** @private */
|
|
@@ -26,7 +28,7 @@ export interface QueueSaver {
|
|
|
26
28
|
options: QueueSaverOptions;
|
|
27
29
|
}
|
|
28
30
|
export declare class QueueSaver {
|
|
29
|
-
constructor(
|
|
31
|
+
constructor(options: QueueSaverOptions);
|
|
30
32
|
get(guildId: string): Promise<Partial<StoredQueue>>;
|
|
31
33
|
delete(guildId: string): Promise<any>;
|
|
32
34
|
set(guildId: string, value: any): Promise<any>;
|
|
@@ -59,7 +61,7 @@ export declare class Queue {
|
|
|
59
61
|
static readonly StaticSymbol: Symbol;
|
|
60
62
|
private managerUtils;
|
|
61
63
|
private queueChanges;
|
|
62
|
-
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver,
|
|
64
|
+
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
|
|
63
65
|
/**
|
|
64
66
|
* Utils for a Queue
|
|
65
67
|
*/
|
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Queue = exports.QueueChangesWatcher = exports.DefaultQueueStore = exports.QueueSaver = void 0;
|
|
4
4
|
const Utils_1 = require("./Utils");
|
|
5
5
|
class QueueSaver {
|
|
6
|
-
constructor(
|
|
7
|
-
this._ =
|
|
8
|
-
this.options =
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this._ = options.queueStore || new DefaultQueueStore();
|
|
8
|
+
this.options = {
|
|
9
|
+
maxPreviousTracks: options.maxPreviousTracks
|
|
10
|
+
};
|
|
9
11
|
}
|
|
10
12
|
async get(guildId) {
|
|
11
13
|
return await this._.parse(await this._.get(guildId));
|
|
@@ -66,8 +68,8 @@ class Queue {
|
|
|
66
68
|
static StaticSymbol = Utils_1.QueueSymbol;
|
|
67
69
|
managerUtils = new Utils_1.ManagerUitls();
|
|
68
70
|
queueChanges;
|
|
69
|
-
constructor(guildId, data = {}, QueueSaver,
|
|
70
|
-
this.queueChanges = queueChangesWatcher || null;
|
|
71
|
+
constructor(guildId, data = {}, QueueSaver, queueOptions) {
|
|
72
|
+
this.queueChanges = queueOptions.queueChangesWatcher || null;
|
|
71
73
|
this.guildId = guildId;
|
|
72
74
|
this.QueueSaver = QueueSaver;
|
|
73
75
|
this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LavalinkFilterData } from "./Filters";
|
|
2
2
|
import { LavalinkManager } from "./LavalinkManager";
|
|
3
|
-
import { LavalinkNode, NodeStats } from "./Node";
|
|
3
|
+
import { LavalinkNode, LavalinkNodeOptions, NodeStats } from "./Node";
|
|
4
4
|
import { PlayOptions } from "./Player";
|
|
5
5
|
import { Queue } from "./Queue";
|
|
6
6
|
import { PluginInfo, Track } from "./Track";
|
|
@@ -40,10 +40,20 @@ export interface ManagerUitls {
|
|
|
40
40
|
export declare class ManagerUitls {
|
|
41
41
|
constructor(LavalinkManager?: LavalinkManager);
|
|
42
42
|
buildTrack(data: any, requester: any): Track;
|
|
43
|
+
/**
|
|
44
|
+
* Validate if a data is equal to a node
|
|
45
|
+
* @param data
|
|
46
|
+
*/
|
|
47
|
+
isNode(data: LavalinkNode): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Validate if a data is equal to node options
|
|
50
|
+
* @param data
|
|
51
|
+
*/
|
|
52
|
+
isNodeOptions(data: LavalinkNodeOptions | any): boolean;
|
|
43
53
|
/**
|
|
44
54
|
* Validate if a data is euqal to a track
|
|
45
|
-
* @param
|
|
46
|
-
* @returns
|
|
55
|
+
* @param data the Track to validate
|
|
56
|
+
* @returns
|
|
47
57
|
*/
|
|
48
58
|
isTrack(data: Track | any): boolean;
|
|
49
59
|
validatedQuery(queryString: string, node: LavalinkNode): void;
|
|
@@ -85,6 +95,8 @@ export declare class MiniMap<K, V> extends Map<K, V> {
|
|
|
85
95
|
filter<This, K2 extends K>(fn: (this: This, value: V, key: K, miniMap: this) => key is K2, thisArg: This): MiniMap<K2, V>;
|
|
86
96
|
filter<This, V2 extends V>(fn: (this: This, value: V, key: K, miniMap: this) => value is V2, thisArg: This): MiniMap<K, V2>;
|
|
87
97
|
filter<This>(fn: (this: This, value: V, key: K, miniMap: this) => boolean, thisArg: This): MiniMap<K, V>;
|
|
98
|
+
toJSON(): V[];
|
|
99
|
+
private static defaultSort;
|
|
88
100
|
/**
|
|
89
101
|
* Maps each item to another value into an array. Identical in behavior to
|
|
90
102
|
* [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
|
|
@@ -41,10 +41,58 @@ class ManagerUitls {
|
|
|
41
41
|
throw new RangeError(`Argument "data" is not a valid track: ${error.message}`);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Validate if a data is equal to a node
|
|
46
|
+
* @param data
|
|
47
|
+
*/
|
|
48
|
+
isNode(data) {
|
|
49
|
+
if (!data)
|
|
50
|
+
return false;
|
|
51
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(data));
|
|
52
|
+
if (!keys.includes("constructor"))
|
|
53
|
+
return false;
|
|
54
|
+
if (!keys.length)
|
|
55
|
+
return false;
|
|
56
|
+
// all required functions
|
|
57
|
+
if (!["connect", "destroy", "destroyPlayer", "fetchAllPlayers", "fetchInfo", "fetchPlayer", "fetchStats", "fetchVersion", "request", "updatePlayer", "updateSession"].every(v => keys.includes(v)))
|
|
58
|
+
return false;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Validate if a data is equal to node options
|
|
63
|
+
* @param data
|
|
64
|
+
*/
|
|
65
|
+
isNodeOptions(data) {
|
|
66
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
67
|
+
return false;
|
|
68
|
+
if (typeof data.host !== "string" || !data.host.length)
|
|
69
|
+
return false;
|
|
70
|
+
if (typeof data.port !== "number" || isNaN(data.port) || data.port < 0 || data.port > 65535)
|
|
71
|
+
return false;
|
|
72
|
+
if (typeof data.authorization !== "string" || !data.authorization.length)
|
|
73
|
+
return false;
|
|
74
|
+
if ("secure" in data && typeof data.secure !== "boolean")
|
|
75
|
+
return false;
|
|
76
|
+
if ("sessionId" in data && typeof data.sessionId !== "string")
|
|
77
|
+
return false;
|
|
78
|
+
if ("id" in data && typeof data.id !== "string")
|
|
79
|
+
return false;
|
|
80
|
+
if ("regions" in data && (!Array.isArray(data.regions) || !data.regions.every(v => typeof v === "string")))
|
|
81
|
+
return false;
|
|
82
|
+
if ("poolOptions" in data && typeof data.poolOptions !== "object")
|
|
83
|
+
return false;
|
|
84
|
+
if ("retryAmount" in data && (typeof data.retryAmount !== "number" || isNaN(data.retryAmount) || data.retryAmount <= 0))
|
|
85
|
+
return false;
|
|
86
|
+
if ("retryDelay" in data && (typeof data.retryDelay !== "number" || isNaN(data.retryDelay) || data.retryDelay <= 0))
|
|
87
|
+
return false;
|
|
88
|
+
if ("requestTimeout" in data && (typeof data.requestTimeout !== "number" || isNaN(data.requestTimeout) || data.requestTimeout <= 0))
|
|
89
|
+
return false;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
44
92
|
/**
|
|
45
93
|
* Validate if a data is euqal to a track
|
|
46
|
-
* @param
|
|
47
|
-
* @returns
|
|
94
|
+
* @param data the Track to validate
|
|
95
|
+
* @returns
|
|
48
96
|
*/
|
|
49
97
|
isTrack(data) {
|
|
50
98
|
return typeof data?.encoded === "string" && typeof data?.info === "object";
|
|
@@ -152,6 +200,13 @@ class MiniMap extends Map {
|
|
|
152
200
|
}
|
|
153
201
|
return results;
|
|
154
202
|
}
|
|
203
|
+
toJSON() {
|
|
204
|
+
// toJSON is called recursively by JSON.stringify.
|
|
205
|
+
return [...this.values()];
|
|
206
|
+
}
|
|
207
|
+
static defaultSort(firstValue, secondValue) {
|
|
208
|
+
return Number(firstValue > secondValue) || Number(firstValue === secondValue) - 1;
|
|
209
|
+
}
|
|
155
210
|
map(fn, thisArg) {
|
|
156
211
|
if (typeof thisArg !== 'undefined')
|
|
157
212
|
fn = fn.bind(thisArg);
|
|
@@ -170,11 +225,11 @@ async function queueTrackEnd(queue, addBackToQueue = false) {
|
|
|
170
225
|
if (queue.previous.length > queue.options.maxPreviousTracks)
|
|
171
226
|
queue.previous.splice(queue.options.maxPreviousTracks, queue.previous.length);
|
|
172
227
|
}
|
|
173
|
-
// change the current Track to the next upcoming one
|
|
174
|
-
queue.current = queue.tracks.shift() || null;
|
|
175
228
|
// and if repeatMode == queue, add it back to the queue!
|
|
176
229
|
if (addBackToQueue && queue.current)
|
|
177
230
|
queue.tracks.push(queue.current);
|
|
231
|
+
// change the current Track to the next upcoming one
|
|
232
|
+
queue.current = queue.tracks.shift() || null;
|
|
178
233
|
// save it in the DB
|
|
179
234
|
await queue.utils.save();
|
|
180
235
|
// return the new current Track
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
|
-
import {
|
|
4
|
+
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";
|
|
@@ -44,11 +44,11 @@ export interface LavalinkPlayerOptions {
|
|
|
44
44
|
export interface ManagerOptions {
|
|
45
45
|
nodes: LavalinkNodeOptions[];
|
|
46
46
|
queueOptions?: QueueSaverOptions;
|
|
47
|
-
queueStore?: StoreManager;
|
|
48
|
-
queueChangesWatcher?: QueueChangesWatcher;
|
|
49
47
|
client?: BotClientOptions;
|
|
50
48
|
playerOptions?: LavalinkPlayerOptions;
|
|
51
49
|
autoSkip?: boolean;
|
|
50
|
+
defaultLeastUsedNodeSortType?: "memory" | "calls" | "players";
|
|
51
|
+
defaultLeastLoadNodeSortType?: "cpu" | "memory";
|
|
52
52
|
/** @async */
|
|
53
53
|
sendToShard: (guildId: string, payload: GuildShardPayload) => void;
|
|
54
54
|
}
|
|
@@ -10,36 +10,97 @@ export class LavalinkManager extends EventEmitter {
|
|
|
10
10
|
initiated = false;
|
|
11
11
|
players = new MiniMap();
|
|
12
12
|
applyDefaultOptions() {
|
|
13
|
+
if (!this.options.playerOptions)
|
|
14
|
+
this.options.playerOptions = {
|
|
15
|
+
applyVolumeAsFilter: false,
|
|
16
|
+
clientBasedPositionUpdateInterval: 100,
|
|
17
|
+
defaultSearchPlatform: "ytsearch",
|
|
18
|
+
onDisconnect: {
|
|
19
|
+
destroyPlayer: true,
|
|
20
|
+
autoReconnect: false
|
|
21
|
+
},
|
|
22
|
+
onEmptyQueue: {
|
|
23
|
+
autoPlayFunction: null,
|
|
24
|
+
destroyAfterMs: undefined
|
|
25
|
+
},
|
|
26
|
+
requesterTransformer: (requester) => {
|
|
27
|
+
// if it's already the transformed requester
|
|
28
|
+
if (typeof requester === "object" && "avatar" in requester && Object.keys(requester).length === 3)
|
|
29
|
+
return requester;
|
|
30
|
+
// if it's still a discord.js User
|
|
31
|
+
if (typeof requester === "object" && "displayAvatarURL" in requester) { // it's a user
|
|
32
|
+
return {
|
|
33
|
+
id: requester.id,
|
|
34
|
+
username: requester.username,
|
|
35
|
+
avatar: requester.displayAvatarURL(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// if it's non of the above
|
|
39
|
+
return { id: requester.toString(), username: "unknown" }; // reteurn something that makes sense for you!
|
|
40
|
+
},
|
|
41
|
+
volumeDecrementer: 1
|
|
42
|
+
};
|
|
43
|
+
if (!this.options.autoSkip)
|
|
44
|
+
this.options.autoSkip = true;
|
|
45
|
+
if (!this.options.defaultLeastLoadNodeSortType)
|
|
46
|
+
this.options.defaultLeastLoadNodeSortType = "memory";
|
|
47
|
+
if (!this.options.defaultLeastUsedNodeSortType)
|
|
48
|
+
this.options.defaultLeastUsedNodeSortType = "players";
|
|
13
49
|
if (!this.options.playerOptions.defaultSearchPlatform)
|
|
14
50
|
this.options.playerOptions.defaultSearchPlatform = "ytsearch";
|
|
51
|
+
// default queue options
|
|
52
|
+
if (!this.options.queueOptions)
|
|
53
|
+
this.options.queueOptions = {
|
|
54
|
+
maxPreviousTracks: 25,
|
|
55
|
+
queueChangesWatcher: null,
|
|
56
|
+
queueStore: new DefaultQueueStore()
|
|
57
|
+
};
|
|
15
58
|
if (typeof this.options?.queueOptions?.maxPreviousTracks !== "number" || this.options.queueOptions.maxPreviousTracks < 0)
|
|
16
59
|
this.options.queueOptions.maxPreviousTracks = 25;
|
|
17
60
|
return;
|
|
18
61
|
}
|
|
19
62
|
validateAndApply(options) {
|
|
63
|
+
if (typeof options.sendToShard !== "function")
|
|
64
|
+
throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
|
|
65
|
+
// only check in .init()
|
|
66
|
+
// 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");
|
|
67
|
+
if (options.autoSkip && typeof options.autoSkip !== "boolean")
|
|
68
|
+
throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
|
|
69
|
+
if (options.defaultLeastLoadNodeSortType && !["memory", "cpu"].includes(options.defaultLeastLoadNodeSortType))
|
|
70
|
+
throw new SyntaxError("ManagerOption.defaultLeastLoadNodeSortType must be 'memory' | 'cpu'");
|
|
71
|
+
if (options.defaultLeastUsedNodeSortType && !["memory", "players", "calls"].includes(options.defaultLeastUsedNodeSortType))
|
|
72
|
+
throw new SyntaxError("ManagerOption.defaultLeastLoadNodeSortType must be 'memory' | 'calls' | 'players'");
|
|
73
|
+
if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
|
|
74
|
+
throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
|
|
20
75
|
/* QUEUE STORE */
|
|
21
|
-
if (options.queueStore) {
|
|
22
|
-
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueStore));
|
|
76
|
+
if (options.queueOptions?.queueStore) {
|
|
77
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueStore));
|
|
23
78
|
const requiredKeys = ["get", "set", "stringify", "parse", "delete"];
|
|
24
|
-
if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueStore[v] === "function"))
|
|
25
|
-
throw new SyntaxError(`The provided QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
|
|
79
|
+
if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueStore[v] === "function"))
|
|
80
|
+
throw new SyntaxError(`The provided ManagerOption.QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
|
|
26
81
|
}
|
|
27
82
|
else
|
|
28
|
-
this.options.queueStore = new DefaultQueueStore();
|
|
83
|
+
this.options.queueOptions.queueStore = new DefaultQueueStore();
|
|
84
|
+
/* QUEUE WATCHER */
|
|
85
|
+
if (options.queueOptions?.queueChangesWatcher) {
|
|
86
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueChangesWatcher));
|
|
87
|
+
const requiredKeys = ["tracksAdd", "tracksRemoved", "shuffled"];
|
|
88
|
+
if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueChangesWatcher[v] === "function"))
|
|
89
|
+
throw new SyntaxError(`The provided ManagerOption.QueueChangesWatcher, does not have all required functions: ${requiredKeys.join(", ")}`);
|
|
90
|
+
}
|
|
29
91
|
}
|
|
30
92
|
constructor(options) {
|
|
31
93
|
super();
|
|
94
|
+
if (!options)
|
|
95
|
+
throw new SyntaxError("No Manager Options Provided");
|
|
32
96
|
// create options
|
|
33
|
-
this.options =
|
|
34
|
-
|
|
35
|
-
...options
|
|
36
|
-
};
|
|
97
|
+
this.options = options;
|
|
98
|
+
this.utils = new ManagerUitls(this);
|
|
37
99
|
// use the validators
|
|
38
|
-
this.applyDefaultOptions();
|
|
39
100
|
this.validateAndApply(options);
|
|
101
|
+
this.applyDefaultOptions();
|
|
40
102
|
// create classes
|
|
41
103
|
this.nodeManager = new NodeManager(this);
|
|
42
|
-
this.utils = new ManagerUitls(this);
|
|
43
104
|
}
|
|
44
105
|
createPlayer(options) {
|
|
45
106
|
if (this.players.has(options.guildId))
|
|
@@ -149,7 +149,7 @@ export class LavalinkNode {
|
|
|
149
149
|
}
|
|
150
150
|
/** Get the id of the node */
|
|
151
151
|
get id() {
|
|
152
|
-
return this.options.id || this.options.host
|
|
152
|
+
return this.options.id || `${this.options.host}:${this.options.port}`;
|
|
153
153
|
}
|
|
154
154
|
/**
|
|
155
155
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
@@ -527,14 +527,14 @@ export class LavalinkNode {
|
|
|
527
527
|
return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
528
528
|
// If a track had an error while starting
|
|
529
529
|
if (["loadFailed", "cleanup"].includes(payload.reason)) {
|
|
530
|
-
await queueTrackEnd(player.queue);
|
|
530
|
+
await queueTrackEnd(player.queue, false);
|
|
531
531
|
// if no track available, end queue
|
|
532
532
|
if (!player.queue.current)
|
|
533
533
|
return this.queueEnd(player, track, payload);
|
|
534
534
|
// fire event
|
|
535
535
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
536
536
|
// play track if autoSkip is true
|
|
537
|
-
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({
|
|
537
|
+
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
538
538
|
}
|
|
539
539
|
// remove tracks from the queue
|
|
540
540
|
if (player.repeatMode !== "track")
|
|
@@ -545,7 +545,7 @@ export class LavalinkNode {
|
|
|
545
545
|
// fire event
|
|
546
546
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
547
547
|
// play track if autoSkip is true
|
|
548
|
-
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({
|
|
548
|
+
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
549
549
|
}
|
|
550
550
|
async queueEnd(player, track, payload) {
|
|
551
551
|
player.queue.current = null;
|
|
@@ -555,7 +555,7 @@ export class LavalinkNode {
|
|
|
555
555
|
if (player.queue.tracks.length > 0)
|
|
556
556
|
await queueTrackEnd(player.queue, player.repeatMode === "queue");
|
|
557
557
|
if (player.queue.current)
|
|
558
|
-
return player.play({
|
|
558
|
+
return player.play({ noReplace: true, paused: false });
|
|
559
559
|
}
|
|
560
560
|
if (payload?.reason !== "stopped") {
|
|
561
561
|
await player.queue.utils.save();
|
|
@@ -586,7 +586,7 @@ export class LavalinkNode {
|
|
|
586
586
|
if (!player.queue.current)
|
|
587
587
|
return this.queueEnd(player, track, payload);
|
|
588
588
|
// play track if autoSkip is true
|
|
589
|
-
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({
|
|
589
|
+
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
590
590
|
}
|
|
591
591
|
async trackError(player, track, payload) {
|
|
592
592
|
this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
|
|
@@ -596,7 +596,7 @@ export class LavalinkNode {
|
|
|
596
596
|
if (!player.queue.current)
|
|
597
597
|
return this.queueEnd(player, track, payload);
|
|
598
598
|
// play track if autoSkip is true
|
|
599
|
-
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({
|
|
599
|
+
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
600
600
|
}
|
|
601
601
|
socketClosed(player, payload) {
|
|
602
602
|
return this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
|
|
@@ -56,6 +56,17 @@ export declare class NodeManager extends EventEmitter {
|
|
|
56
56
|
constructor(LavalinkManager: LavalinkManager);
|
|
57
57
|
createNode(options: LavalinkNodeOptions): LavalinkNode;
|
|
58
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[];
|
|
59
70
|
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
60
71
|
}
|
|
61
72
|
export {};
|
|
@@ -11,14 +11,71 @@ export class NodeManager extends EventEmitter {
|
|
|
11
11
|
this.LavalinkManager.options.nodes.forEach(node => this.createNode(node));
|
|
12
12
|
}
|
|
13
13
|
createNode(options) {
|
|
14
|
-
if (this.nodes.has(options.id || options.host))
|
|
15
|
-
return this.nodes.get(options.id || options.host);
|
|
14
|
+
if (this.nodes.has(options.id || `${options.host}:${options.port}`))
|
|
15
|
+
return this.nodes.get(options.id || `${options.host}:${options.port}`);
|
|
16
16
|
const newNode = new LavalinkNode(options, this);
|
|
17
17
|
this.nodes.set(newNode.id, newNode);
|
|
18
18
|
return newNode;
|
|
19
19
|
}
|
|
20
20
|
get leastUsedNodes() {
|
|
21
|
-
|
|
21
|
+
if (this.LavalinkManager.options.defaultLeastUsedNodeSortType === "memory")
|
|
22
|
+
return this.leastUsedNodesMemory;
|
|
23
|
+
else if (this.LavalinkManager.options.defaultLeastUsedNodeSortType === "calls")
|
|
24
|
+
return this.leastUsedNodesCalls;
|
|
25
|
+
else
|
|
26
|
+
return this.leastUsedNodesPlayers; // this.options.defaultLeastUsedNodeSortType === "players"
|
|
27
|
+
}
|
|
28
|
+
/** Returns the least used Nodes sorted by amount of calls. */
|
|
29
|
+
get leastUsedNodesCalls() {
|
|
30
|
+
return [...this.nodes.values()]
|
|
31
|
+
.filter((node) => node.connected)
|
|
32
|
+
.sort((a, b) => b.calls - a.calls); // client sided sorting
|
|
33
|
+
}
|
|
34
|
+
/** Returns the least used Nodes sorted by amount of players. */
|
|
35
|
+
get leastUsedNodesPlayers() {
|
|
36
|
+
return [...this.nodes.values()]
|
|
37
|
+
.filter((node) => node.connected)
|
|
38
|
+
.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
|
|
39
|
+
}
|
|
40
|
+
/** Returns the least used Nodes sorted by amount of memory usage. */
|
|
41
|
+
get leastUsedNodesMemory() {
|
|
42
|
+
return [...this.nodes.values()]
|
|
43
|
+
.filter((node) => node.connected)
|
|
44
|
+
.sort((a, b) => (b.stats?.memory?.used || 0) - (a.stats?.memory?.used || 0)); // sort after memory
|
|
45
|
+
}
|
|
46
|
+
/** Returns the least system load Nodes. */
|
|
47
|
+
get leastLoadNodes() {
|
|
48
|
+
if (this.LavalinkManager.options.defaultLeastLoadNodeSortType === "cpu")
|
|
49
|
+
return this.leastLoadNodesCpu;
|
|
50
|
+
else
|
|
51
|
+
return this.leastLoadNodesMemory; // this.options.defaultLeastLoadNodeSortType === "memory"
|
|
52
|
+
}
|
|
53
|
+
get leastLoadNodesMemory() {
|
|
54
|
+
return [...this.nodes.values()]
|
|
55
|
+
.filter((node) => node.connected)
|
|
56
|
+
.sort((a, b) => {
|
|
57
|
+
const aload = a.stats.memory?.used
|
|
58
|
+
? a.stats.memory.used
|
|
59
|
+
: 0;
|
|
60
|
+
const bload = b.stats.memory?.used
|
|
61
|
+
? b.stats.memory.used
|
|
62
|
+
: 0;
|
|
63
|
+
return aload - bload;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** Returns the least system load Nodes. */
|
|
67
|
+
get leastLoadNodesCpu() {
|
|
68
|
+
return [...this.nodes.values()]
|
|
69
|
+
.filter((node) => node.connected)
|
|
70
|
+
.sort((a, b) => {
|
|
71
|
+
const aload = a.stats.cpu
|
|
72
|
+
? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100
|
|
73
|
+
: 0;
|
|
74
|
+
const bload = b.stats.cpu
|
|
75
|
+
? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100
|
|
76
|
+
: 0;
|
|
77
|
+
return aload - bload;
|
|
78
|
+
});
|
|
22
79
|
}
|
|
23
80
|
deleteNode(node) {
|
|
24
81
|
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes[0];
|
|
@@ -63,7 +63,9 @@ export class Player {
|
|
|
63
63
|
this.guildId = this.options.guildId;
|
|
64
64
|
this.voiceChannelId = this.options.voiceChannelId;
|
|
65
65
|
this.textChannelId = this.options.textChannelId || null;
|
|
66
|
-
this.node = this.
|
|
66
|
+
this.node = typeof this.options.node === "string" ? this.LavalinkManager.nodeManager.nodes.get(this.options.node) : this.options.node;
|
|
67
|
+
if (!this.node || typeof this.node?.request !== "function")
|
|
68
|
+
this.node = this.LavalinkManager.nodeManager.leastUsedNodes.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || this.LavalinkManager.nodeManager.leastUsedNodes[0] || null;
|
|
67
69
|
if (!this.node)
|
|
68
70
|
throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
|
|
69
71
|
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
@@ -71,7 +73,7 @@ export class Player {
|
|
|
71
73
|
this.LavalinkManager.emit("playerCreate", this);
|
|
72
74
|
if (typeof options.volume === "number" && !isNaN(options.volume))
|
|
73
75
|
this.setVolume(options.volume);
|
|
74
|
-
this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.
|
|
76
|
+
this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
|
|
75
77
|
}
|
|
76
78
|
/**
|
|
77
79
|
* Set custom data.
|
|
@@ -18,6 +18,8 @@ export interface StoreManager extends Record<any, any> {
|
|
|
18
18
|
}
|
|
19
19
|
export interface QueueSaverOptions {
|
|
20
20
|
maxPreviousTracks: number;
|
|
21
|
+
queueStore?: StoreManager;
|
|
22
|
+
queueChangesWatcher?: QueueChangesWatcher;
|
|
21
23
|
}
|
|
22
24
|
export interface QueueSaver {
|
|
23
25
|
/** @private */
|
|
@@ -26,7 +28,7 @@ export interface QueueSaver {
|
|
|
26
28
|
options: QueueSaverOptions;
|
|
27
29
|
}
|
|
28
30
|
export declare class QueueSaver {
|
|
29
|
-
constructor(
|
|
31
|
+
constructor(options: QueueSaverOptions);
|
|
30
32
|
get(guildId: string): Promise<Partial<StoredQueue>>;
|
|
31
33
|
delete(guildId: string): Promise<any>;
|
|
32
34
|
set(guildId: string, value: any): Promise<any>;
|
|
@@ -59,7 +61,7 @@ export declare class Queue {
|
|
|
59
61
|
static readonly StaticSymbol: Symbol;
|
|
60
62
|
private managerUtils;
|
|
61
63
|
private queueChanges;
|
|
62
|
-
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver,
|
|
64
|
+
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
|
|
63
65
|
/**
|
|
64
66
|
* Utils for a Queue
|
|
65
67
|
*/
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ManagerUitls, QueueSymbol } from "./Utils";
|
|
2
2
|
export class QueueSaver {
|
|
3
|
-
constructor(
|
|
4
|
-
this._ =
|
|
5
|
-
this.options =
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this._ = options.queueStore || new DefaultQueueStore();
|
|
5
|
+
this.options = {
|
|
6
|
+
maxPreviousTracks: options.maxPreviousTracks
|
|
7
|
+
};
|
|
6
8
|
}
|
|
7
9
|
async get(guildId) {
|
|
8
10
|
return await this._.parse(await this._.get(guildId));
|
|
@@ -60,8 +62,8 @@ export class Queue {
|
|
|
60
62
|
static StaticSymbol = QueueSymbol;
|
|
61
63
|
managerUtils = new ManagerUitls();
|
|
62
64
|
queueChanges;
|
|
63
|
-
constructor(guildId, data = {}, QueueSaver,
|
|
64
|
-
this.queueChanges = queueChangesWatcher || null;
|
|
65
|
+
constructor(guildId, data = {}, QueueSaver, queueOptions) {
|
|
66
|
+
this.queueChanges = queueOptions.queueChangesWatcher || null;
|
|
65
67
|
this.guildId = guildId;
|
|
66
68
|
this.QueueSaver = QueueSaver;
|
|
67
69
|
this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LavalinkFilterData } from "./Filters";
|
|
2
2
|
import { LavalinkManager } from "./LavalinkManager";
|
|
3
|
-
import { LavalinkNode, NodeStats } from "./Node";
|
|
3
|
+
import { LavalinkNode, LavalinkNodeOptions, NodeStats } from "./Node";
|
|
4
4
|
import { PlayOptions } from "./Player";
|
|
5
5
|
import { Queue } from "./Queue";
|
|
6
6
|
import { PluginInfo, Track } from "./Track";
|
|
@@ -40,10 +40,20 @@ export interface ManagerUitls {
|
|
|
40
40
|
export declare class ManagerUitls {
|
|
41
41
|
constructor(LavalinkManager?: LavalinkManager);
|
|
42
42
|
buildTrack(data: any, requester: any): Track;
|
|
43
|
+
/**
|
|
44
|
+
* Validate if a data is equal to a node
|
|
45
|
+
* @param data
|
|
46
|
+
*/
|
|
47
|
+
isNode(data: LavalinkNode): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Validate if a data is equal to node options
|
|
50
|
+
* @param data
|
|
51
|
+
*/
|
|
52
|
+
isNodeOptions(data: LavalinkNodeOptions | any): boolean;
|
|
43
53
|
/**
|
|
44
54
|
* Validate if a data is euqal to a track
|
|
45
|
-
* @param
|
|
46
|
-
* @returns
|
|
55
|
+
* @param data the Track to validate
|
|
56
|
+
* @returns
|
|
47
57
|
*/
|
|
48
58
|
isTrack(data: Track | any): boolean;
|
|
49
59
|
validatedQuery(queryString: string, node: LavalinkNode): void;
|
|
@@ -85,6 +95,8 @@ export declare class MiniMap<K, V> extends Map<K, V> {
|
|
|
85
95
|
filter<This, K2 extends K>(fn: (this: This, value: V, key: K, miniMap: this) => key is K2, thisArg: This): MiniMap<K2, V>;
|
|
86
96
|
filter<This, V2 extends V>(fn: (this: This, value: V, key: K, miniMap: this) => value is V2, thisArg: This): MiniMap<K, V2>;
|
|
87
97
|
filter<This>(fn: (this: This, value: V, key: K, miniMap: this) => boolean, thisArg: This): MiniMap<K, V>;
|
|
98
|
+
toJSON(): V[];
|
|
99
|
+
private static defaultSort;
|
|
88
100
|
/**
|
|
89
101
|
* Maps each item to another value into an array. Identical in behavior to
|
|
90
102
|
* [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
|
|
@@ -38,10 +38,58 @@ export class ManagerUitls {
|
|
|
38
38
|
throw new RangeError(`Argument "data" is not a valid track: ${error.message}`);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate if a data is equal to a node
|
|
43
|
+
* @param data
|
|
44
|
+
*/
|
|
45
|
+
isNode(data) {
|
|
46
|
+
if (!data)
|
|
47
|
+
return false;
|
|
48
|
+
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(data));
|
|
49
|
+
if (!keys.includes("constructor"))
|
|
50
|
+
return false;
|
|
51
|
+
if (!keys.length)
|
|
52
|
+
return false;
|
|
53
|
+
// all required functions
|
|
54
|
+
if (!["connect", "destroy", "destroyPlayer", "fetchAllPlayers", "fetchInfo", "fetchPlayer", "fetchStats", "fetchVersion", "request", "updatePlayer", "updateSession"].every(v => keys.includes(v)))
|
|
55
|
+
return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate if a data is equal to node options
|
|
60
|
+
* @param data
|
|
61
|
+
*/
|
|
62
|
+
isNodeOptions(data) {
|
|
63
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
64
|
+
return false;
|
|
65
|
+
if (typeof data.host !== "string" || !data.host.length)
|
|
66
|
+
return false;
|
|
67
|
+
if (typeof data.port !== "number" || isNaN(data.port) || data.port < 0 || data.port > 65535)
|
|
68
|
+
return false;
|
|
69
|
+
if (typeof data.authorization !== "string" || !data.authorization.length)
|
|
70
|
+
return false;
|
|
71
|
+
if ("secure" in data && typeof data.secure !== "boolean")
|
|
72
|
+
return false;
|
|
73
|
+
if ("sessionId" in data && typeof data.sessionId !== "string")
|
|
74
|
+
return false;
|
|
75
|
+
if ("id" in data && typeof data.id !== "string")
|
|
76
|
+
return false;
|
|
77
|
+
if ("regions" in data && (!Array.isArray(data.regions) || !data.regions.every(v => typeof v === "string")))
|
|
78
|
+
return false;
|
|
79
|
+
if ("poolOptions" in data && typeof data.poolOptions !== "object")
|
|
80
|
+
return false;
|
|
81
|
+
if ("retryAmount" in data && (typeof data.retryAmount !== "number" || isNaN(data.retryAmount) || data.retryAmount <= 0))
|
|
82
|
+
return false;
|
|
83
|
+
if ("retryDelay" in data && (typeof data.retryDelay !== "number" || isNaN(data.retryDelay) || data.retryDelay <= 0))
|
|
84
|
+
return false;
|
|
85
|
+
if ("requestTimeout" in data && (typeof data.requestTimeout !== "number" || isNaN(data.requestTimeout) || data.requestTimeout <= 0))
|
|
86
|
+
return false;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
41
89
|
/**
|
|
42
90
|
* Validate if a data is euqal to a track
|
|
43
|
-
* @param
|
|
44
|
-
* @returns
|
|
91
|
+
* @param data the Track to validate
|
|
92
|
+
* @returns
|
|
45
93
|
*/
|
|
46
94
|
isTrack(data) {
|
|
47
95
|
return typeof data?.encoded === "string" && typeof data?.info === "object";
|
|
@@ -148,6 +196,13 @@ export class MiniMap extends Map {
|
|
|
148
196
|
}
|
|
149
197
|
return results;
|
|
150
198
|
}
|
|
199
|
+
toJSON() {
|
|
200
|
+
// toJSON is called recursively by JSON.stringify.
|
|
201
|
+
return [...this.values()];
|
|
202
|
+
}
|
|
203
|
+
static defaultSort(firstValue, secondValue) {
|
|
204
|
+
return Number(firstValue > secondValue) || Number(firstValue === secondValue) - 1;
|
|
205
|
+
}
|
|
151
206
|
map(fn, thisArg) {
|
|
152
207
|
if (typeof thisArg !== 'undefined')
|
|
153
208
|
fn = fn.bind(thisArg);
|
|
@@ -165,11 +220,11 @@ export async function queueTrackEnd(queue, addBackToQueue = false) {
|
|
|
165
220
|
if (queue.previous.length > queue.options.maxPreviousTracks)
|
|
166
221
|
queue.previous.splice(queue.options.maxPreviousTracks, queue.previous.length);
|
|
167
222
|
}
|
|
168
|
-
// change the current Track to the next upcoming one
|
|
169
|
-
queue.current = queue.tracks.shift() || null;
|
|
170
223
|
// and if repeatMode == queue, add it back to the queue!
|
|
171
224
|
if (addBackToQueue && queue.current)
|
|
172
225
|
queue.tracks.push(queue.current);
|
|
226
|
+
// change the current Track to the next upcoming one
|
|
227
|
+
queue.current = queue.tracks.shift() || null;
|
|
173
228
|
// save it in the DB
|
|
174
229
|
await queue.utils.save();
|
|
175
230
|
// return the new current Track
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
|
-
import {
|
|
4
|
+
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";
|
|
@@ -44,11 +44,11 @@ export interface LavalinkPlayerOptions {
|
|
|
44
44
|
export interface ManagerOptions {
|
|
45
45
|
nodes: LavalinkNodeOptions[];
|
|
46
46
|
queueOptions?: QueueSaverOptions;
|
|
47
|
-
queueStore?: StoreManager;
|
|
48
|
-
queueChangesWatcher?: QueueChangesWatcher;
|
|
49
47
|
client?: BotClientOptions;
|
|
50
48
|
playerOptions?: LavalinkPlayerOptions;
|
|
51
49
|
autoSkip?: boolean;
|
|
50
|
+
defaultLeastUsedNodeSortType?: "memory" | "calls" | "players";
|
|
51
|
+
defaultLeastLoadNodeSortType?: "cpu" | "memory";
|
|
52
52
|
/** @async */
|
|
53
53
|
sendToShard: (guildId: string, payload: GuildShardPayload) => void;
|
|
54
54
|
}
|
|
@@ -56,6 +56,17 @@ export declare class NodeManager extends EventEmitter {
|
|
|
56
56
|
constructor(LavalinkManager: LavalinkManager);
|
|
57
57
|
createNode(options: LavalinkNodeOptions): LavalinkNode;
|
|
58
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[];
|
|
59
70
|
deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
|
|
60
71
|
}
|
|
61
72
|
export {};
|
|
@@ -18,6 +18,8 @@ export interface StoreManager extends Record<any, any> {
|
|
|
18
18
|
}
|
|
19
19
|
export interface QueueSaverOptions {
|
|
20
20
|
maxPreviousTracks: number;
|
|
21
|
+
queueStore?: StoreManager;
|
|
22
|
+
queueChangesWatcher?: QueueChangesWatcher;
|
|
21
23
|
}
|
|
22
24
|
export interface QueueSaver {
|
|
23
25
|
/** @private */
|
|
@@ -26,7 +28,7 @@ export interface QueueSaver {
|
|
|
26
28
|
options: QueueSaverOptions;
|
|
27
29
|
}
|
|
28
30
|
export declare class QueueSaver {
|
|
29
|
-
constructor(
|
|
31
|
+
constructor(options: QueueSaverOptions);
|
|
30
32
|
get(guildId: string): Promise<Partial<StoredQueue>>;
|
|
31
33
|
delete(guildId: string): Promise<any>;
|
|
32
34
|
set(guildId: string, value: any): Promise<any>;
|
|
@@ -59,7 +61,7 @@ export declare class Queue {
|
|
|
59
61
|
static readonly StaticSymbol: Symbol;
|
|
60
62
|
private managerUtils;
|
|
61
63
|
private queueChanges;
|
|
62
|
-
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver,
|
|
64
|
+
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
|
|
63
65
|
/**
|
|
64
66
|
* Utils for a Queue
|
|
65
67
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LavalinkFilterData } from "./Filters";
|
|
2
2
|
import { LavalinkManager } from "./LavalinkManager";
|
|
3
|
-
import { LavalinkNode, NodeStats } from "./Node";
|
|
3
|
+
import { LavalinkNode, LavalinkNodeOptions, NodeStats } from "./Node";
|
|
4
4
|
import { PlayOptions } from "./Player";
|
|
5
5
|
import { Queue } from "./Queue";
|
|
6
6
|
import { PluginInfo, Track } from "./Track";
|
|
@@ -40,10 +40,20 @@ export interface ManagerUitls {
|
|
|
40
40
|
export declare class ManagerUitls {
|
|
41
41
|
constructor(LavalinkManager?: LavalinkManager);
|
|
42
42
|
buildTrack(data: any, requester: any): Track;
|
|
43
|
+
/**
|
|
44
|
+
* Validate if a data is equal to a node
|
|
45
|
+
* @param data
|
|
46
|
+
*/
|
|
47
|
+
isNode(data: LavalinkNode): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Validate if a data is equal to node options
|
|
50
|
+
* @param data
|
|
51
|
+
*/
|
|
52
|
+
isNodeOptions(data: LavalinkNodeOptions | any): boolean;
|
|
43
53
|
/**
|
|
44
54
|
* Validate if a data is euqal to a track
|
|
45
|
-
* @param
|
|
46
|
-
* @returns
|
|
55
|
+
* @param data the Track to validate
|
|
56
|
+
* @returns
|
|
47
57
|
*/
|
|
48
58
|
isTrack(data: Track | any): boolean;
|
|
49
59
|
validatedQuery(queryString: string, node: LavalinkNode): void;
|
|
@@ -85,6 +95,8 @@ export declare class MiniMap<K, V> extends Map<K, V> {
|
|
|
85
95
|
filter<This, K2 extends K>(fn: (this: This, value: V, key: K, miniMap: this) => key is K2, thisArg: This): MiniMap<K2, V>;
|
|
86
96
|
filter<This, V2 extends V>(fn: (this: This, value: V, key: K, miniMap: this) => value is V2, thisArg: This): MiniMap<K, V2>;
|
|
87
97
|
filter<This>(fn: (this: This, value: V, key: K, miniMap: this) => boolean, thisArg: This): MiniMap<K, V>;
|
|
98
|
+
toJSON(): V[];
|
|
99
|
+
private static defaultSort;
|
|
88
100
|
/**
|
|
89
101
|
* Maps each item to another value into an array. Identical in behavior to
|
|
90
102
|
* [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
|
package/package.json
CHANGED