lavalink-client 1.0.4 → 1.0.6
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/README.md +33 -98
- package/dist/cjs/structures/LavalinkManager.d.ts +19 -14
- package/dist/cjs/structures/LavalinkManager.js +3 -14
- package/dist/cjs/structures/Node.d.ts +3 -3
- package/dist/cjs/structures/Node.js +16 -11
- package/dist/cjs/structures/NodeManager.d.ts +1 -12
- package/dist/cjs/structures/NodeManager.js +53 -60
- package/dist/cjs/structures/Player.d.ts +4 -4
- package/dist/cjs/structures/Player.js +20 -7
- package/dist/cjs/structures/Queue.d.ts +9 -9
- package/dist/cjs/structures/Queue.js +24 -23
- package/dist/cjs/structures/Track.d.ts +14 -3
- package/dist/cjs/structures/Utils.d.ts +20 -5
- package/dist/cjs/structures/Utils.js +135 -15
- package/dist/esm/structures/LavalinkManager.d.ts +19 -14
- package/dist/esm/structures/LavalinkManager.js +3 -14
- package/dist/esm/structures/Node.d.ts +3 -3
- package/dist/esm/structures/Node.js +16 -11
- package/dist/esm/structures/NodeManager.d.ts +1 -12
- package/dist/esm/structures/NodeManager.js +53 -60
- package/dist/esm/structures/Player.d.ts +4 -4
- package/dist/esm/structures/Player.js +20 -7
- package/dist/esm/structures/Queue.d.ts +9 -9
- package/dist/esm/structures/Queue.js +25 -24
- package/dist/esm/structures/Track.d.ts +14 -3
- package/dist/esm/structures/Utils.d.ts +20 -5
- package/dist/esm/structures/Utils.js +135 -15
- package/dist/types/structures/LavalinkManager.d.ts +19 -14
- package/dist/types/structures/Node.d.ts +3 -3
- package/dist/types/structures/NodeManager.d.ts +1 -12
- package/dist/types/structures/Player.d.ts +4 -4
- package/dist/types/structures/Queue.d.ts +9 -9
- package/dist/types/structures/Track.d.ts +14 -3
- package/dist/types/structures/Utils.d.ts +20 -5
- package/package.json +1 -1
|
@@ -42,10 +42,6 @@ export class LavalinkManager extends EventEmitter {
|
|
|
42
42
|
};
|
|
43
43
|
if (!this.options.autoSkip)
|
|
44
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";
|
|
49
45
|
if (!this.options.playerOptions.defaultSearchPlatform)
|
|
50
46
|
this.options.playerOptions.defaultSearchPlatform = "ytsearch";
|
|
51
47
|
// default queue options
|
|
@@ -63,13 +59,9 @@ export class LavalinkManager extends EventEmitter {
|
|
|
63
59
|
if (typeof options.sendToShard !== "function")
|
|
64
60
|
throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
|
|
65
61
|
// only check in .init()
|
|
66
|
-
// if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string
|
|
62
|
+
// 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");
|
|
67
63
|
if (options.autoSkip && typeof options.autoSkip !== "boolean")
|
|
68
64
|
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
65
|
if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
|
|
74
66
|
throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
|
|
75
67
|
/* QUEUE STORE */
|
|
@@ -154,9 +146,7 @@ export class LavalinkManager extends EventEmitter {
|
|
|
154
146
|
* @param data
|
|
155
147
|
*/
|
|
156
148
|
async sendRawData(data) {
|
|
157
|
-
if (!this.initiated)
|
|
158
|
-
return;
|
|
159
|
-
if (!("t" in data))
|
|
149
|
+
if (!this.initiated || !("t" in data))
|
|
160
150
|
return;
|
|
161
151
|
// for channel Delete
|
|
162
152
|
if ("CHANNEL_DELETE" === data.t) {
|
|
@@ -164,9 +154,8 @@ export class LavalinkManager extends EventEmitter {
|
|
|
164
154
|
if (!update.guild_id)
|
|
165
155
|
return;
|
|
166
156
|
const player = this.getPlayer(update.guild_id);
|
|
167
|
-
if (player.voiceChannelId === update.id)
|
|
157
|
+
if (player && player.voiceChannelId === update.id)
|
|
168
158
|
return player.destroy(DestroyReasons.ChannelDeleted);
|
|
169
|
-
}
|
|
170
159
|
}
|
|
171
160
|
// for voice updates
|
|
172
161
|
if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
|
|
@@ -4,7 +4,7 @@ import { NodeManager } from "./NodeManager";
|
|
|
4
4
|
import internal from "stream";
|
|
5
5
|
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64 } from "./Utils";
|
|
6
6
|
import { DestroyReasonsType } from "./Player";
|
|
7
|
-
import {
|
|
7
|
+
import { Track } from "./Track";
|
|
8
8
|
/** Modifies any outgoing REST requests. */
|
|
9
9
|
export type ModifyRequest = (options: Dispatcher.RequestOptions) => void;
|
|
10
10
|
export interface LavalinkNodeOptions {
|
|
@@ -185,13 +185,13 @@ export declare class LavalinkNode {
|
|
|
185
185
|
* @param encoded
|
|
186
186
|
* @returns
|
|
187
187
|
*/
|
|
188
|
-
singleTrack: (encoded: Base64) => Promise<
|
|
188
|
+
singleTrack: (encoded: Base64, requester: unknown) => Promise<Track>;
|
|
189
189
|
/**
|
|
190
190
|
*
|
|
191
191
|
* @param encodeds Decodes multiple tracks into their info
|
|
192
192
|
* @returns
|
|
193
193
|
*/
|
|
194
|
-
multipleTracks: (encodeds: Base64[]) => Promise<
|
|
194
|
+
multipleTracks: (encodeds: Base64[], requester: unknown) => Promise<Track[]>;
|
|
195
195
|
};
|
|
196
196
|
/**
|
|
197
197
|
* Request Lavalink statistics.
|
|
@@ -133,9 +133,8 @@ export class LavalinkNode {
|
|
|
133
133
|
return;
|
|
134
134
|
const headers = {
|
|
135
135
|
Authorization: this.options.authorization,
|
|
136
|
-
"Num-Shards": String(this.NodeManager.LavalinkManager.options.client.shards || "auto"),
|
|
137
136
|
"User-Id": this.NodeManager.LavalinkManager.options.client.id,
|
|
138
|
-
"
|
|
137
|
+
"Client-Name": this.NodeManager.LavalinkManager.options.client.username || "Lavalink-Client",
|
|
139
138
|
};
|
|
140
139
|
if (typeof this.options.sessionId === "string" || typeof sessionId === "string") {
|
|
141
140
|
headers["Session-Id"] = this.options.sessionId || sessionId;
|
|
@@ -224,25 +223,27 @@ export class LavalinkNode {
|
|
|
224
223
|
* @param encoded
|
|
225
224
|
* @returns
|
|
226
225
|
*/
|
|
227
|
-
singleTrack: async (encoded) => {
|
|
226
|
+
singleTrack: async (encoded, requester) => {
|
|
228
227
|
if (!encoded)
|
|
229
228
|
throw new SyntaxError("No encoded (Base64 string) was provided");
|
|
230
|
-
return
|
|
229
|
+
// return the decoded + builded track
|
|
230
|
+
return this.NodeManager.LavalinkManager.utils.buildTrack(await this.request(`/decodetrack?encodedTrack=${encoded}`), requester);
|
|
231
231
|
},
|
|
232
232
|
/**
|
|
233
233
|
*
|
|
234
234
|
* @param encodeds Decodes multiple tracks into their info
|
|
235
235
|
* @returns
|
|
236
236
|
*/
|
|
237
|
-
multipleTracks: async (encodeds) => {
|
|
237
|
+
multipleTracks: async (encodeds, requester) => {
|
|
238
238
|
if (!Array.isArray(encodeds) || !encodeds.every(v => typeof v === "string" && v.length > 1))
|
|
239
239
|
throw new SyntaxError("You need to provide encodeds, which is an array of base64 strings");
|
|
240
|
+
// return the decoded + builded tracks
|
|
240
241
|
return await this.request(`/decodetracks`, r => {
|
|
241
242
|
r.method = "POST";
|
|
242
243
|
r.body = JSON.stringify(encodeds);
|
|
243
244
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
244
245
|
r.headers["Content-Type"] = "application/json";
|
|
245
|
-
});
|
|
246
|
+
}).then((r) => r.map(track => this.NodeManager.LavalinkManager.utils.buildTrack(track, requester)));
|
|
246
247
|
}
|
|
247
248
|
};
|
|
248
249
|
/**
|
|
@@ -473,6 +474,7 @@ export class LavalinkNode {
|
|
|
473
474
|
player.filterManager.filterUpdatedState = 0;
|
|
474
475
|
}
|
|
475
476
|
}
|
|
477
|
+
this.NodeManager.LavalinkManager.emit("playerUpdate", player);
|
|
476
478
|
break;
|
|
477
479
|
case "event":
|
|
478
480
|
this.handleEvent(payload);
|
|
@@ -519,6 +521,7 @@ export class LavalinkNode {
|
|
|
519
521
|
return this.NodeManager.LavalinkManager.emit("trackStart", player, track, payload);
|
|
520
522
|
}
|
|
521
523
|
async trackEnd(player, track, payload) {
|
|
524
|
+
console.log(payload.reason);
|
|
522
525
|
// If there are no songs in the queue
|
|
523
526
|
if (!player.queue.tracks.length && player.repeatMode === "off")
|
|
524
527
|
return this.queueEnd(player, track, payload);
|
|
@@ -527,7 +530,7 @@ export class LavalinkNode {
|
|
|
527
530
|
return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
528
531
|
// If a track had an error while starting
|
|
529
532
|
if (["loadFailed", "cleanup"].includes(payload.reason)) {
|
|
530
|
-
await queueTrackEnd(player
|
|
533
|
+
await queueTrackEnd(player);
|
|
531
534
|
// if no track available, end queue
|
|
532
535
|
if (!player.queue.current)
|
|
533
536
|
return this.queueEnd(player, track, payload);
|
|
@@ -538,7 +541,7 @@ export class LavalinkNode {
|
|
|
538
541
|
}
|
|
539
542
|
// remove tracks from the queue
|
|
540
543
|
if (player.repeatMode !== "track")
|
|
541
|
-
await queueTrackEnd(player
|
|
544
|
+
await queueTrackEnd(player);
|
|
542
545
|
// if no track available, end queue
|
|
543
546
|
if (!player.queue.current)
|
|
544
547
|
return this.queueEnd(player, track, payload);
|
|
@@ -548,15 +551,17 @@ export class LavalinkNode {
|
|
|
548
551
|
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
549
552
|
}
|
|
550
553
|
async queueEnd(player, track, payload) {
|
|
554
|
+
// add previous track to the queue!
|
|
551
555
|
player.queue.current = null;
|
|
552
556
|
player.playing = false;
|
|
553
557
|
if (typeof this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function") {
|
|
554
558
|
await this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track);
|
|
555
559
|
if (player.queue.tracks.length > 0)
|
|
556
|
-
await queueTrackEnd(player
|
|
560
|
+
await queueTrackEnd(player);
|
|
557
561
|
if (player.queue.current)
|
|
558
562
|
return player.play({ noReplace: true, paused: false });
|
|
559
563
|
}
|
|
564
|
+
player.queue.previous.unshift(track);
|
|
560
565
|
if (payload?.reason !== "stopped") {
|
|
561
566
|
await player.queue.utils.save();
|
|
562
567
|
}
|
|
@@ -581,7 +586,7 @@ export class LavalinkNode {
|
|
|
581
586
|
if (!player.queue.tracks.length && player.repeatMode === "off")
|
|
582
587
|
return;
|
|
583
588
|
// remove the current track, and enqueue the next one
|
|
584
|
-
await queueTrackEnd(player
|
|
589
|
+
await queueTrackEnd(player);
|
|
585
590
|
// if no track available, end queue
|
|
586
591
|
if (!player.queue.current)
|
|
587
592
|
return this.queueEnd(player, track, payload);
|
|
@@ -591,7 +596,7 @@ export class LavalinkNode {
|
|
|
591
596
|
async trackError(player, track, payload) {
|
|
592
597
|
this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
|
|
593
598
|
// remove the current track, and enqueue the next one
|
|
594
|
-
await queueTrackEnd(player
|
|
599
|
+
await queueTrackEnd(player);
|
|
595
600
|
// if no track available, end queue
|
|
596
601
|
if (!player.queue.current)
|
|
597
602
|
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
|
-
|
|
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 {};
|
|
@@ -17,68 +17,61 @@ export class NodeManager extends EventEmitter {
|
|
|
17
17
|
this.nodes.set(newNode.id, newNode);
|
|
18
18
|
return newNode;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
});
|
|
20
|
+
leastUsedNodes(sortType = "players") {
|
|
21
|
+
switch (sortType) {
|
|
22
|
+
case "memory":
|
|
23
|
+
{
|
|
24
|
+
return [...this.nodes.values()]
|
|
25
|
+
.filter((node) => node.connected)
|
|
26
|
+
.sort((a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0)); // sort after memor
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
case "cpuLavalink":
|
|
30
|
+
{
|
|
31
|
+
return [...this.nodes.values()]
|
|
32
|
+
.filter((node) => node.connected)
|
|
33
|
+
.sort((a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0)); // sort after memor
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
case "cpuSystem":
|
|
37
|
+
{
|
|
38
|
+
return [...this.nodes.values()]
|
|
39
|
+
.filter((node) => node.connected)
|
|
40
|
+
.sort((a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0)); // sort after memor
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
case "calls":
|
|
44
|
+
{
|
|
45
|
+
return [...this.nodes.values()]
|
|
46
|
+
.filter((node) => node.connected)
|
|
47
|
+
.sort((a, b) => a.calls - b.calls); // client sided sorting
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case "playingPlayers":
|
|
51
|
+
{
|
|
52
|
+
return [...this.nodes.values()]
|
|
53
|
+
.filter((node) => node.connected)
|
|
54
|
+
.sort((a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0));
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
case "players":
|
|
58
|
+
{
|
|
59
|
+
return [...this.nodes.values()]
|
|
60
|
+
.filter((node) => node.connected)
|
|
61
|
+
.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
{
|
|
66
|
+
return [...this.nodes.values()]
|
|
67
|
+
.filter((node) => node.connected)
|
|
68
|
+
.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
79
72
|
}
|
|
80
73
|
deleteNode(node) {
|
|
81
|
-
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes[0];
|
|
74
|
+
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes()[0];
|
|
82
75
|
if (!decodeNode)
|
|
83
76
|
throw new Error("Node was not found");
|
|
84
77
|
decodeNode.destroy(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>):
|
|
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<
|
|
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<
|
|
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
|
}
|
|
@@ -64,8 +64,10 @@ export class Player {
|
|
|
64
64
|
this.voiceChannelId = this.options.voiceChannelId;
|
|
65
65
|
this.textChannelId = this.options.textChannelId || null;
|
|
66
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
|
|
68
|
-
|
|
67
|
+
if (!this.node || typeof this.node.request !== "function") {
|
|
68
|
+
const least = this.LavalinkManager.nodeManager.leastUsedNodes();
|
|
69
|
+
this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
|
|
70
|
+
}
|
|
69
71
|
if (!this.node)
|
|
70
72
|
throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
|
|
71
73
|
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
@@ -120,10 +122,22 @@ export class Player {
|
|
|
120
122
|
}
|
|
121
123
|
if (options?.track && this.LavalinkManager.utils.isTrack(options?.track)) {
|
|
122
124
|
await this.queue.add(options?.track, 0);
|
|
123
|
-
await queueTrackEnd(this
|
|
125
|
+
await queueTrackEnd(this);
|
|
124
126
|
}
|
|
125
127
|
if (!this.queue.current && this.queue.tracks.length)
|
|
126
|
-
await queueTrackEnd(this
|
|
128
|
+
await queueTrackEnd(this);
|
|
129
|
+
// @ts-ignore
|
|
130
|
+
if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
|
|
131
|
+
try {
|
|
132
|
+
this.queue.current = await this.LavalinkManager.utils.getClosestTrack({ ...(this.queue.current || {}) }, this);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
this.LavalinkManager.emit("trackError", this, this.queue.current, error);
|
|
136
|
+
if (this.queue.tracks[0])
|
|
137
|
+
return this.play();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
127
141
|
const track = this.queue.current;
|
|
128
142
|
if (!track)
|
|
129
143
|
throw new Error(`There is no Track in the Queue, nor provided in the PlayOptions`);
|
|
@@ -274,8 +288,7 @@ export class Player {
|
|
|
274
288
|
async setRepeatMode(repeatMode) {
|
|
275
289
|
if (!["off", "track", "queue"].includes(repeatMode))
|
|
276
290
|
throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
|
|
277
|
-
this.repeatMode = repeatMode;
|
|
278
|
-
return;
|
|
291
|
+
return this.repeatMode = repeatMode;
|
|
279
292
|
}
|
|
280
293
|
/**
|
|
281
294
|
* Skip the current song, or a specific amount of songs
|
|
@@ -375,6 +388,7 @@ export class Player {
|
|
|
375
388
|
toJSON() {
|
|
376
389
|
return {
|
|
377
390
|
guildId: this.guildId,
|
|
391
|
+
options: this.options,
|
|
378
392
|
voiceChannelId: this.voiceChannelId,
|
|
379
393
|
textChannelId: this.textChannelId,
|
|
380
394
|
position: this.position,
|
|
@@ -387,7 +401,6 @@ export class Player {
|
|
|
387
401
|
createdTimeStamp: this.createdTimeStamp,
|
|
388
402
|
filters: this.filterManager?.data || {},
|
|
389
403
|
equalizer: this.filterManager?.equalizerBands || [],
|
|
390
|
-
queue: this.queue?.utils?.getStored?.() || { current: null, tracks: [], previous: [] },
|
|
391
404
|
nodeId: this.node?.id,
|
|
392
405
|
};
|
|
393
406
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Track } from "./Track";
|
|
1
|
+
import { Track, UnresolvedTrack } from "./Track";
|
|
2
2
|
export interface StoredQueue {
|
|
3
3
|
current: Track | null;
|
|
4
4
|
previous: Track[];
|
|
@@ -45,23 +45,23 @@ export declare class DefaultQueueStore {
|
|
|
45
45
|
}
|
|
46
46
|
export declare class QueueChangesWatcher {
|
|
47
47
|
constructor();
|
|
48
|
-
tracksAdd(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
49
|
-
tracksRemoved(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
48
|
+
tracksAdd(guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
49
|
+
tracksRemoved(guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
50
50
|
shuffled(guildId: string, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
|
|
51
51
|
}
|
|
52
52
|
export declare class Queue {
|
|
53
|
-
readonly tracks: Track[];
|
|
53
|
+
readonly tracks: (Track | UnresolvedTrack)[];
|
|
54
54
|
readonly previous: Track[];
|
|
55
55
|
current: Track | null;
|
|
56
56
|
options: {
|
|
57
57
|
maxPreviousTracks: number;
|
|
58
58
|
};
|
|
59
59
|
private readonly guildId;
|
|
60
|
-
|
|
61
|
-
static readonly StaticSymbol: Symbol;
|
|
60
|
+
private readonly QueueSaver;
|
|
62
61
|
private managerUtils;
|
|
63
62
|
private queueChanges;
|
|
64
63
|
constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
|
|
64
|
+
private applyData;
|
|
65
65
|
/**
|
|
66
66
|
* Utils for a Queue
|
|
67
67
|
*/
|
|
@@ -79,7 +79,7 @@ export declare class Queue {
|
|
|
79
79
|
/**
|
|
80
80
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
|
|
81
81
|
*/
|
|
82
|
-
|
|
82
|
+
toJSON: () => StoredQueue;
|
|
83
83
|
/**
|
|
84
84
|
* Get the Total Duration of the Queue-Songs summed up
|
|
85
85
|
* @returns {number}
|
|
@@ -97,7 +97,7 @@ export declare class Queue {
|
|
|
97
97
|
* @param {number} index At what position to add the Track
|
|
98
98
|
* @returns {number} Queue-Size (for the next Tracks)
|
|
99
99
|
*/
|
|
100
|
-
add(TrackOrTracks: Track | Track[], index?: number): any;
|
|
100
|
+
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): any;
|
|
101
101
|
/**
|
|
102
102
|
* Splice the tracks in the Queue
|
|
103
103
|
* @param {number} index Where to remove the Track
|
|
@@ -105,5 +105,5 @@ export declare class Queue {
|
|
|
105
105
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
106
106
|
* @returns {Track} Spliced Track
|
|
107
107
|
*/
|
|
108
|
-
splice(index: number, amount: number, TrackOrTracks?: Track | Track[]): any;
|
|
108
|
+
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): any;
|
|
109
109
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ManagerUitls
|
|
1
|
+
import { ManagerUitls } from "./Utils";
|
|
2
2
|
export class QueueSaver {
|
|
3
3
|
constructor(options) {
|
|
4
4
|
this._ = options.queueStore || new DefaultQueueStore();
|
|
@@ -59,7 +59,6 @@ export class Queue {
|
|
|
59
59
|
options = { maxPreviousTracks: 25 };
|
|
60
60
|
guildId = "";
|
|
61
61
|
QueueSaver = null;
|
|
62
|
-
static StaticSymbol = QueueSymbol;
|
|
63
62
|
managerUtils = new ManagerUitls();
|
|
64
63
|
queueChanges;
|
|
65
64
|
constructor(guildId, data = {}, QueueSaver, queueOptions) {
|
|
@@ -68,8 +67,10 @@ export class Queue {
|
|
|
68
67
|
this.QueueSaver = QueueSaver;
|
|
69
68
|
this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
|
|
70
69
|
this.current = this.managerUtils.isTrack(data.current) ? data.current : null;
|
|
71
|
-
this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track)) : [];
|
|
72
|
-
this.tracks = Array.isArray(data.tracks) && data.tracks.some(track => this.managerUtils.isTrack(track)) ? data.tracks.filter(track => this.managerUtils.isTrack(track)) : [];
|
|
70
|
+
this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
|
|
71
|
+
this.tracks = Array.isArray(data.tracks) && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.tracks.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
|
|
72
|
+
}
|
|
73
|
+
applyData(data) {
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
76
|
* Utils for a Queue
|
|
@@ -81,7 +82,7 @@ export class Queue {
|
|
|
81
82
|
save: async () => {
|
|
82
83
|
if (this.previous.length > this.options.maxPreviousTracks)
|
|
83
84
|
this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
84
|
-
return await this.QueueSaver.set(this.guildId, this.utils.
|
|
85
|
+
return await this.QueueSaver.set(this.guildId, this.utils.toJSON());
|
|
85
86
|
},
|
|
86
87
|
/**
|
|
87
88
|
* Sync the current queue database/server with the cached one
|
|
@@ -91,12 +92,12 @@ export class Queue {
|
|
|
91
92
|
const data = await this.QueueSaver.get(this.guildId);
|
|
92
93
|
if (!data)
|
|
93
94
|
return console.log("No data found to sync for guildId: ", this.guildId);
|
|
94
|
-
if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current))
|
|
95
|
+
if (!dontSyncCurrent && !this.current && (this.managerUtils.isTrack(data.current)))
|
|
95
96
|
this.current = data.current;
|
|
96
|
-
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track)))
|
|
97
|
-
this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track)));
|
|
98
|
-
if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track)))
|
|
99
|
-
this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter(track => this.managerUtils.isTrack(track)));
|
|
97
|
+
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
|
|
98
|
+
this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
99
|
+
if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
|
|
100
|
+
this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
100
101
|
await this.utils.save();
|
|
101
102
|
return;
|
|
102
103
|
},
|
|
@@ -106,13 +107,13 @@ export class Queue {
|
|
|
106
107
|
/**
|
|
107
108
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
|
|
108
109
|
*/
|
|
109
|
-
|
|
110
|
+
toJSON: () => {
|
|
110
111
|
if (this.previous.length > this.options.maxPreviousTracks)
|
|
111
112
|
this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
112
113
|
return {
|
|
113
|
-
current: this.current,
|
|
114
|
-
previous: this.previous,
|
|
115
|
-
tracks: this.tracks,
|
|
114
|
+
current: this.current ? { ...this.current } : null,
|
|
115
|
+
previous: this.previous ? [...this.previous] : [],
|
|
116
|
+
tracks: this.tracks ? [...this.tracks] : [],
|
|
116
117
|
};
|
|
117
118
|
},
|
|
118
119
|
/**
|
|
@@ -128,7 +129,7 @@ export class Queue {
|
|
|
128
129
|
* @returns Amount of Tracks in the Queue
|
|
129
130
|
*/
|
|
130
131
|
async shuffle() {
|
|
131
|
-
const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.
|
|
132
|
+
const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.toJSON() : null;
|
|
132
133
|
if (this.tracks.length <= 1)
|
|
133
134
|
return this.tracks.length;
|
|
134
135
|
// swap #1 and #2 if only 2 tracks.
|
|
@@ -143,7 +144,7 @@ export class Queue {
|
|
|
143
144
|
}
|
|
144
145
|
// LOG
|
|
145
146
|
if (typeof this.queueChanges?.shuffled === "function")
|
|
146
|
-
this.queueChanges.shuffled(this.guildId, oldStored, this.utils.
|
|
147
|
+
this.queueChanges.shuffled(this.guildId, oldStored, this.utils.toJSON());
|
|
147
148
|
await this.utils.save();
|
|
148
149
|
return this.tracks.length;
|
|
149
150
|
}
|
|
@@ -155,14 +156,14 @@ export class Queue {
|
|
|
155
156
|
*/
|
|
156
157
|
async add(TrackOrTracks, index) {
|
|
157
158
|
if (typeof index === "number" && index >= 0 && index < this.tracks.length)
|
|
158
|
-
return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
|
|
159
|
-
const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.
|
|
159
|
+
return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
|
|
160
|
+
const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.toJSON() : null;
|
|
160
161
|
// add the track(s)
|
|
161
|
-
this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
|
|
162
|
+
this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
|
|
162
163
|
// log if available
|
|
163
164
|
if (typeof this.queueChanges?.tracksAdd === "function")
|
|
164
165
|
try {
|
|
165
|
-
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)), this.tracks.length, oldStored, this.utils.
|
|
166
|
+
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), this.tracks.length, oldStored, this.utils.toJSON());
|
|
166
167
|
}
|
|
167
168
|
catch (e) { /* */ }
|
|
168
169
|
// save the queue
|
|
@@ -178,7 +179,7 @@ export class Queue {
|
|
|
178
179
|
* @returns {Track} Spliced Track
|
|
179
180
|
*/
|
|
180
181
|
async splice(index, amount, TrackOrTracks) {
|
|
181
|
-
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.
|
|
182
|
+
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
|
|
182
183
|
// if no tracks to splice, add the tracks
|
|
183
184
|
if (!this.tracks.length) {
|
|
184
185
|
if (TrackOrTracks)
|
|
@@ -188,17 +189,17 @@ export class Queue {
|
|
|
188
189
|
// Log if available
|
|
189
190
|
if ((TrackOrTracks) && typeof this.queueChanges?.tracksAdd === "function")
|
|
190
191
|
try {
|
|
191
|
-
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)), index, oldStored, this.utils.
|
|
192
|
+
this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), index, oldStored, this.utils.toJSON());
|
|
192
193
|
}
|
|
193
194
|
catch (e) { /* */ }
|
|
194
195
|
// remove the tracks (and add the new ones)
|
|
195
|
-
let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v))) : this.tracks.splice(index, amount);
|
|
196
|
+
let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))) : this.tracks.splice(index, amount);
|
|
196
197
|
// get the spliced array
|
|
197
198
|
spliced = (Array.isArray(spliced) ? spliced : [spliced]);
|
|
198
199
|
// Log if available
|
|
199
200
|
if (typeof this.queueChanges?.tracksRemoved === "function")
|
|
200
201
|
try {
|
|
201
|
-
this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.
|
|
202
|
+
this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
|
|
202
203
|
}
|
|
203
204
|
catch (e) { /* */ }
|
|
204
205
|
// save the queue
|