lavalink-client 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -20
- package/dist/cjs/index.d.ts +7 -1
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/structures/Constants.d.ts +40 -0
- package/dist/cjs/structures/Constants.js +244 -0
- package/dist/cjs/structures/CustomSearches/BandCampSearch.d.ts +2 -2
- package/dist/cjs/structures/Filters.d.ts +2 -217
- package/dist/cjs/structures/Filters.js +12 -236
- package/dist/cjs/structures/LavalinkManager.d.ts +31 -166
- package/dist/cjs/structures/LavalinkManager.js +60 -8
- package/dist/cjs/structures/LavalinkManagerStatics.d.ts +1 -1
- package/dist/cjs/structures/LavalinkManagerStatics.js +1 -1
- package/dist/cjs/structures/Node.d.ts +15 -156
- package/dist/cjs/structures/Node.js +140 -51
- package/dist/cjs/structures/NodeManager.d.ts +54 -52
- package/dist/cjs/structures/NodeManager.js +77 -5
- package/dist/cjs/structures/Player.d.ts +31 -124
- package/dist/cjs/structures/Player.js +78 -43
- package/dist/cjs/structures/Queue.d.ts +113 -42
- package/dist/cjs/structures/Queue.js +169 -8
- package/dist/cjs/structures/Types/Filters.d.ts +190 -0
- package/dist/cjs/structures/Types/Manager.d.ts +184 -0
- package/dist/cjs/structures/Types/Manager.js +2 -0
- package/dist/cjs/structures/Types/Node.d.ts +216 -0
- package/dist/cjs/structures/Types/Node.js +2 -0
- package/dist/cjs/structures/Types/Player.d.ts +108 -0
- package/dist/cjs/structures/Types/Player.js +2 -0
- package/dist/cjs/structures/Types/Queue.d.ts +34 -0
- package/dist/cjs/structures/Types/Queue.js +2 -0
- package/dist/cjs/structures/{Track.d.ts → Types/Track.d.ts} +4 -2
- package/dist/cjs/structures/Types/Track.js +2 -0
- package/dist/cjs/structures/Types/Utils.d.ts +367 -0
- package/dist/cjs/structures/Types/Utils.js +2 -0
- package/dist/cjs/structures/Utils.d.ts +13 -369
- package/dist/cjs/structures/Utils.js +40 -18
- package/dist/esm/index.d.ts +7 -1
- package/dist/esm/index.js +7 -1
- package/dist/esm/structures/Constants.d.ts +40 -0
- package/dist/esm/structures/Constants.js +241 -0
- package/dist/esm/structures/CustomSearches/BandCampSearch.d.ts +2 -2
- package/dist/esm/structures/Filters.d.ts +2 -217
- package/dist/esm/structures/Filters.js +7 -231
- package/dist/esm/structures/LavalinkManager.d.ts +31 -166
- package/dist/esm/structures/LavalinkManager.js +58 -6
- package/dist/esm/structures/LavalinkManagerStatics.d.ts +1 -1
- package/dist/esm/structures/LavalinkManagerStatics.js +1 -1
- package/dist/esm/structures/Node.d.ts +15 -156
- package/dist/esm/structures/Node.js +132 -43
- package/dist/esm/structures/NodeManager.d.ts +54 -52
- package/dist/esm/structures/NodeManager.js +74 -2
- package/dist/esm/structures/Player.d.ts +31 -124
- package/dist/esm/structures/Player.js +77 -42
- package/dist/esm/structures/Queue.d.ts +113 -42
- package/dist/esm/structures/Queue.js +169 -8
- package/dist/esm/structures/Types/Filters.d.ts +190 -0
- package/dist/esm/structures/Types/Manager.d.ts +184 -0
- package/dist/esm/structures/Types/Manager.js +1 -0
- package/dist/esm/structures/Types/Node.d.ts +216 -0
- package/dist/esm/structures/Types/Node.js +1 -0
- package/dist/esm/structures/Types/Player.d.ts +108 -0
- package/dist/esm/structures/Types/Player.js +1 -0
- package/dist/esm/structures/Types/Queue.d.ts +34 -0
- package/dist/esm/structures/Types/Queue.js +1 -0
- package/dist/{types/structures → esm/structures/Types}/Track.d.ts +4 -2
- package/dist/esm/structures/Types/Track.js +1 -0
- package/dist/esm/structures/Types/Utils.d.ts +367 -0
- package/dist/esm/structures/Types/Utils.js +1 -0
- package/dist/esm/structures/Utils.d.ts +13 -369
- package/dist/esm/structures/Utils.js +40 -18
- package/dist/types/index.d.ts +7 -1
- package/dist/types/structures/Constants.d.ts +40 -0
- package/dist/types/structures/CustomSearches/BandCampSearch.d.ts +2 -2
- package/dist/types/structures/Filters.d.ts +2 -217
- package/dist/types/structures/LavalinkManager.d.ts +31 -166
- package/dist/types/structures/LavalinkManagerStatics.d.ts +1 -1
- package/dist/types/structures/Node.d.ts +15 -156
- package/dist/types/structures/NodeManager.d.ts +54 -52
- package/dist/types/structures/Player.d.ts +31 -124
- package/dist/types/structures/Queue.d.ts +113 -42
- package/dist/types/structures/Types/Filters.d.ts +190 -0
- package/dist/types/structures/Types/Manager.d.ts +184 -0
- package/dist/types/structures/Types/Node.d.ts +216 -0
- package/dist/types/structures/Types/Player.d.ts +108 -0
- package/dist/types/structures/Types/Queue.d.ts +34 -0
- package/dist/{esm/structures → types/structures/Types}/Track.d.ts +4 -2
- package/dist/types/structures/Types/Utils.d.ts +367 -0
- package/dist/types/structures/Utils.d.ts +13 -369
- package/package.json +1 -1
- /package/dist/cjs/structures/{Track.js → Types/Filters.js} +0 -0
- /package/dist/esm/structures/{Track.js → Types/Filters.js} +0 -0
|
@@ -1,162 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
/** Ability to manipulate fetch requests */
|
|
8
|
-
export type ModifyRequest = (options: RequestInit & {
|
|
9
|
-
path: string;
|
|
10
|
-
extraQueryUrlParams?: URLSearchParams;
|
|
11
|
-
}) => void;
|
|
12
|
-
export declare const validSponsorBlocks: string[];
|
|
13
|
-
export type SponsorBlockSegment = "sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "filler";
|
|
14
|
-
/**
|
|
15
|
-
* Node Options for creating a lavalink node
|
|
16
|
-
*/
|
|
17
|
-
export interface LavalinkNodeOptions {
|
|
18
|
-
/** The Lavalink Server-Ip / Domain-URL */
|
|
19
|
-
host: string;
|
|
20
|
-
/** The Lavalink Connection Port */
|
|
21
|
-
port: number;
|
|
22
|
-
/** The Lavalink Password / Authorization-Key */
|
|
23
|
-
authorization: string;
|
|
24
|
-
/** Does the Server use ssl (https) */
|
|
25
|
-
secure?: boolean;
|
|
26
|
-
/** RESUME THE PLAYER? by providing a sessionid on the node-creation */
|
|
27
|
-
sessionId?: string;
|
|
28
|
-
/** Add a Custom ID to the node, for later use */
|
|
29
|
-
id?: string;
|
|
30
|
-
/** Voice Regions of this Node */
|
|
31
|
-
regions?: string[];
|
|
32
|
-
/** The retryAmount for the node. */
|
|
33
|
-
retryAmount?: number;
|
|
34
|
-
/** The retryDelay for the node. */
|
|
35
|
-
retryDelay?: number;
|
|
36
|
-
/** signal for cancelling requests - default: AbortSignal.timeout(options.requestSignalTimeoutMS || 10000) - put <= 0 to disable */
|
|
37
|
-
requestSignalTimeoutMS?: number;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Memory Stats object from lavalink
|
|
41
|
-
*/
|
|
42
|
-
export interface MemoryStats {
|
|
43
|
-
/** The free memory of the allocated amount. */
|
|
44
|
-
free: number;
|
|
45
|
-
/** The used memory of the allocated amount. */
|
|
46
|
-
used: number;
|
|
47
|
-
/** The total allocated memory. */
|
|
48
|
-
allocated: number;
|
|
49
|
-
/** The reservable memory. */
|
|
50
|
-
reservable: number;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* CPU Stats object from lavalink
|
|
54
|
-
*/
|
|
55
|
-
export interface CPUStats {
|
|
56
|
-
/** The core amount the host machine has. */
|
|
57
|
-
cores: number;
|
|
58
|
-
/** The system load. */
|
|
59
|
-
systemLoad: number;
|
|
60
|
-
/** The lavalink load. */
|
|
61
|
-
lavalinkLoad: number;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* FrameStats Object from lavalink
|
|
65
|
-
*/
|
|
66
|
-
export interface FrameStats {
|
|
67
|
-
/** The amount of sent frames. */
|
|
68
|
-
sent?: number;
|
|
69
|
-
/** The amount of nulled frames. */
|
|
70
|
-
nulled?: number;
|
|
71
|
-
/** The amount of deficit frames. */
|
|
72
|
-
deficit?: number;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* BaseNodeStats object from Lavalink
|
|
76
|
-
*/
|
|
77
|
-
export interface BaseNodeStats {
|
|
78
|
-
/** The amount of players on the node. */
|
|
79
|
-
players: number;
|
|
80
|
-
/** The amount of playing players on the node. */
|
|
81
|
-
playingPlayers: number;
|
|
82
|
-
/** The uptime for the node. */
|
|
83
|
-
uptime: number;
|
|
84
|
-
/** The memory stats for the node. */
|
|
85
|
-
memory: MemoryStats;
|
|
86
|
-
/** The cpu stats for the node. */
|
|
87
|
-
cpu: CPUStats;
|
|
88
|
-
/** The frame stats for the node. */
|
|
89
|
-
frameStats: FrameStats;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Interface for nodeStats from lavalink
|
|
93
|
-
*/
|
|
94
|
-
export interface NodeStats extends BaseNodeStats {
|
|
95
|
-
/** The frame stats for the node. */
|
|
96
|
-
frameStats: FrameStats;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Entire lavalink information object from lavalink
|
|
100
|
-
*/
|
|
101
|
-
export interface LavalinkInfo {
|
|
102
|
-
/** The version of this Lavalink server */
|
|
103
|
-
version: VersionObject;
|
|
104
|
-
/** The millisecond unix timestamp when this Lavalink jar was built */
|
|
105
|
-
buildTime: number;
|
|
106
|
-
/** The git information of this Lavalink server */
|
|
107
|
-
git: GitObject;
|
|
108
|
-
/** The JVM version this Lavalink server runs on */
|
|
109
|
-
jvm: string;
|
|
110
|
-
/** The Lavaplayer version being used by this server */
|
|
111
|
-
lavaplayer: string;
|
|
112
|
-
/** The enabled source managers for this server */
|
|
113
|
-
sourceManagers: string[];
|
|
114
|
-
/** The enabled filters for this server */
|
|
115
|
-
filters: string[];
|
|
116
|
-
/** The enabled plugins for this server */
|
|
117
|
-
plugins: PluginObject[];
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Lavalink's version object from lavalink
|
|
121
|
-
*/
|
|
122
|
-
export interface VersionObject {
|
|
123
|
-
/** The full version string of this Lavalink server */
|
|
124
|
-
semver: string;
|
|
125
|
-
/** The major version of this Lavalink server */
|
|
126
|
-
major: number;
|
|
127
|
-
/** The minor version of this Lavalink server */
|
|
128
|
-
minor: number;
|
|
129
|
-
/** The patch version of this Lavalink server */
|
|
130
|
-
patch: internal;
|
|
131
|
-
/** The pre-release version according to semver as a . separated list of identifiers */
|
|
132
|
-
preRelease?: string;
|
|
133
|
-
/** The build metadata according to semver as a . separated list of identifiers */
|
|
134
|
-
build?: string;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Git information object from lavalink
|
|
138
|
-
*/
|
|
139
|
-
export interface GitObject {
|
|
140
|
-
/** The branch this Lavalink server was built on */
|
|
141
|
-
branch: string;
|
|
142
|
-
/** The commit this Lavalink server was built on */
|
|
143
|
-
commit: string;
|
|
144
|
-
/** The millisecond unix timestamp for when the commit was created */
|
|
145
|
-
commitTime: string;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Lavalink's plugins object from lavalink's plugin
|
|
149
|
-
*/
|
|
150
|
-
export interface PluginObject {
|
|
151
|
-
/** The name of the plugin */
|
|
152
|
-
name: string;
|
|
153
|
-
/** The version of the plugin */
|
|
154
|
-
version: string;
|
|
155
|
-
}
|
|
1
|
+
import type { Player } from "./Player";
|
|
2
|
+
import type { DestroyReasonsType } from "./Types/Player";
|
|
3
|
+
import type { Track } from "./Types/Track";
|
|
4
|
+
import type { Base64, InvalidLavalinkRestRequest, LavalinkPlayer, LavaSearchQuery, LavaSearchResponse, PlayerUpdateInfo, RoutePlanner, SearchQuery, SearchResult, Session } from "./Types/Utils";
|
|
5
|
+
import type { NodeManager } from "./NodeManager";
|
|
6
|
+
import type { BaseNodeStats, LavalinkInfo, LavalinkNodeOptions, ModifyRequest, NodeStats, SponsorBlockSegment } from "./Types/Node";
|
|
156
7
|
/**
|
|
157
8
|
* Lavalink Node creator class
|
|
158
9
|
*/
|
|
159
10
|
export declare class LavalinkNode {
|
|
11
|
+
private heartBeatPingTimestamp;
|
|
12
|
+
private heartBeatPongTimestamp;
|
|
13
|
+
get heartBeatPing(): number;
|
|
14
|
+
private heartBeatInterval?;
|
|
15
|
+
private pingTimeout?;
|
|
160
16
|
/** The provided Options of the Node */
|
|
161
17
|
options: LavalinkNodeOptions;
|
|
162
18
|
/** The amount of rest calls the node has made. */
|
|
@@ -300,6 +156,7 @@ export declare class LavalinkNode {
|
|
|
300
156
|
* ```
|
|
301
157
|
*/
|
|
302
158
|
connect(sessionId?: string): void;
|
|
159
|
+
private heartBeat;
|
|
303
160
|
/**
|
|
304
161
|
* Get the id of the node
|
|
305
162
|
*
|
|
@@ -332,6 +189,7 @@ export declare class LavalinkNode {
|
|
|
332
189
|
* ```
|
|
333
190
|
*/
|
|
334
191
|
get connected(): boolean;
|
|
192
|
+
isAlive: boolean;
|
|
335
193
|
/**
|
|
336
194
|
* Returns the current ConnectionStatus
|
|
337
195
|
*
|
|
@@ -356,7 +214,7 @@ export declare class LavalinkNode {
|
|
|
356
214
|
* const playersOfLavalink = await node?.fetchAllPlayers();
|
|
357
215
|
* ```
|
|
358
216
|
*/
|
|
359
|
-
fetchAllPlayers(): Promise<LavalinkPlayer[]>;
|
|
217
|
+
fetchAllPlayers(): Promise<LavalinkPlayer[] | InvalidLavalinkRestRequest>;
|
|
360
218
|
/**
|
|
361
219
|
* Gets specific Player Information
|
|
362
220
|
* @returns lavalink player object if player exists on lavalink
|
|
@@ -517,6 +375,7 @@ export declare class LavalinkNode {
|
|
|
517
375
|
private message;
|
|
518
376
|
/** @private middleware util function for handling all kind of events from websocket */
|
|
519
377
|
private handleEvent;
|
|
378
|
+
private getTrackOfPayload;
|
|
520
379
|
/** @private util function for handling trackStart event */
|
|
521
380
|
private trackStart;
|
|
522
381
|
/** @private util function for handling trackEnd event */
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { isAbsolute } from "path";
|
|
2
2
|
import WebSocket from "ws";
|
|
3
|
-
import { DestroyReasons } from "./
|
|
3
|
+
import { DestroyReasons, validSponsorBlocks } from "./Constants";
|
|
4
4
|
import { NodeSymbol, queueTrackEnd } from "./Utils";
|
|
5
|
-
export const validSponsorBlocks = ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "filler"];
|
|
6
5
|
/**
|
|
7
6
|
* Lavalink Node creator class
|
|
8
7
|
*/
|
|
9
8
|
export class LavalinkNode {
|
|
9
|
+
heartBeatPingTimestamp = 0;
|
|
10
|
+
heartBeatPongTimestamp = 0;
|
|
11
|
+
get heartBeatPing() {
|
|
12
|
+
return this.heartBeatPongTimestamp - this.heartBeatPingTimestamp;
|
|
13
|
+
}
|
|
14
|
+
heartBeatInterval;
|
|
15
|
+
pingTimeout;
|
|
10
16
|
/** The provided Options of the Node */
|
|
11
17
|
options;
|
|
12
18
|
/** The amount of rest calls the node has made. */
|
|
@@ -66,8 +72,11 @@ export class LavalinkNode {
|
|
|
66
72
|
this.options = {
|
|
67
73
|
secure: false,
|
|
68
74
|
retryAmount: 5,
|
|
69
|
-
retryDelay:
|
|
75
|
+
retryDelay: 10e3,
|
|
70
76
|
requestSignalTimeoutMS: 10000,
|
|
77
|
+
heartBeatInterval: 30000,
|
|
78
|
+
closeOnError: true,
|
|
79
|
+
enablePingOnStatsCheck: true,
|
|
71
80
|
...options
|
|
72
81
|
};
|
|
73
82
|
this.NodeManager = manager;
|
|
@@ -146,6 +155,8 @@ export class LavalinkNode {
|
|
|
146
155
|
* ```
|
|
147
156
|
*/
|
|
148
157
|
async request(endpoint, modify, parseAsText = false) {
|
|
158
|
+
if (!this.connected)
|
|
159
|
+
throw new Error("The node is not connected to the Lavalink Server!, Please call node.connect() first!");
|
|
149
160
|
const { request, options } = await this.rawRequest(endpoint, modify);
|
|
150
161
|
if (["DELETE", "PUT"].includes(options.method))
|
|
151
162
|
return;
|
|
@@ -230,7 +241,7 @@ export class LavalinkNode {
|
|
|
230
241
|
if (Query.source)
|
|
231
242
|
this.NodeManager.LavalinkManager.utils.validateSourceString(this, Query.source);
|
|
232
243
|
if (/^https?:\/\//.test(Query.query))
|
|
233
|
-
return
|
|
244
|
+
return this.search({ query: Query.query, source: Query.source }, requestUser);
|
|
234
245
|
if (!["spsearch", "sprec", "amsearch", "dzsearch", "dzisrc", "ytmsearch", "ytsearch"].includes(Query.source))
|
|
235
246
|
throw new SyntaxError(`Query.source must be a source from LavaSrc: "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "ytmsearch" | "ytsearch"`);
|
|
236
247
|
if (!this.info.plugins.find(v => v.name === "lavasearch-plugin"))
|
|
@@ -292,7 +303,7 @@ export class LavalinkNode {
|
|
|
292
303
|
async destroyPlayer(guildId) {
|
|
293
304
|
if (!this.sessionId)
|
|
294
305
|
throw new Error("The Lavalink-Node is either not ready, or not up to date!");
|
|
295
|
-
return
|
|
306
|
+
return this.request(`/sessions/${this.sessionId}/players/${guildId}`, r => { r.method = "DELETE"; });
|
|
296
307
|
}
|
|
297
308
|
/**
|
|
298
309
|
* Connect to the Lavalink Node
|
|
@@ -324,6 +335,17 @@ export class LavalinkNode {
|
|
|
324
335
|
this.socket.on("close", (code, reason) => this.close(code, reason?.toString()));
|
|
325
336
|
this.socket.on("message", this.message.bind(this));
|
|
326
337
|
this.socket.on("error", this.error.bind(this));
|
|
338
|
+
// this.socket.on("ping", () => this.heartBeat("ping")); // lavalink doesn'T send ping periodically, therefore we use the stats message
|
|
339
|
+
}
|
|
340
|
+
heartBeat() {
|
|
341
|
+
if (this.pingTimeout)
|
|
342
|
+
clearTimeout(this.pingTimeout);
|
|
343
|
+
this.pingTimeout = setTimeout(() => {
|
|
344
|
+
if (!this.socket)
|
|
345
|
+
return console.error("Node-Ping-Acknowledge-Timeout - Socket not available - maybe reconnecting?");
|
|
346
|
+
this.isAlive = false;
|
|
347
|
+
this.socket.terminate();
|
|
348
|
+
}, 65000); // the stats endpoint get's sent every 60s. se wee add a 5s buffer to make sure we don't miss any stats message
|
|
327
349
|
}
|
|
328
350
|
/**
|
|
329
351
|
* Get the id of the node
|
|
@@ -351,9 +373,11 @@ export class LavalinkNode {
|
|
|
351
373
|
destroy(destroyReason, deleteNode = true) {
|
|
352
374
|
if (!this.connected)
|
|
353
375
|
return;
|
|
354
|
-
const players = this.NodeManager.LavalinkManager.players.filter(p => p.node.id
|
|
376
|
+
const players = this.NodeManager.LavalinkManager.players.filter(p => p.node.id === this.id);
|
|
355
377
|
if (players)
|
|
356
|
-
players.forEach(p =>
|
|
378
|
+
players.forEach(p => {
|
|
379
|
+
p.destroy(destroyReason || DestroyReasons.NodeDestroy);
|
|
380
|
+
});
|
|
357
381
|
this.socket.close(1000, "Node-Destroy");
|
|
358
382
|
this.socket.removeAllListeners();
|
|
359
383
|
this.socket = null;
|
|
@@ -382,6 +406,7 @@ export class LavalinkNode {
|
|
|
382
406
|
return false;
|
|
383
407
|
return this.socket.readyState === WebSocket.OPEN;
|
|
384
408
|
}
|
|
409
|
+
isAlive = false;
|
|
385
410
|
/**
|
|
386
411
|
* Returns the current ConnectionStatus
|
|
387
412
|
*
|
|
@@ -413,11 +438,7 @@ export class LavalinkNode {
|
|
|
413
438
|
async fetchAllPlayers() {
|
|
414
439
|
if (!this.sessionId)
|
|
415
440
|
throw new Error("The Lavalink-Node is either not ready, or not up to date!");
|
|
416
|
-
|
|
417
|
-
if (!Array.isArray(players))
|
|
418
|
-
return [];
|
|
419
|
-
else
|
|
420
|
-
return players;
|
|
441
|
+
return this.request(`/sessions/${this.sessionId}/players`) || [];
|
|
421
442
|
}
|
|
422
443
|
/**
|
|
423
444
|
* Gets specific Player Information
|
|
@@ -432,7 +453,7 @@ export class LavalinkNode {
|
|
|
432
453
|
async fetchPlayer(guildId) {
|
|
433
454
|
if (!this.sessionId)
|
|
434
455
|
throw new Error("The Lavalink-Node is either not ready, or not up to date!");
|
|
435
|
-
return
|
|
456
|
+
return this.request(`/sessions/${this.sessionId}/players/${guildId}`);
|
|
436
457
|
}
|
|
437
458
|
/**
|
|
438
459
|
* Updates the session with and enables/disables resuming and timeout
|
|
@@ -458,7 +479,7 @@ export class LavalinkNode {
|
|
|
458
479
|
enabled: typeof resuming === "boolean" ? resuming : false,
|
|
459
480
|
timeout: typeof resuming === "boolean" && resuming === true ? timeout : null,
|
|
460
481
|
};
|
|
461
|
-
return
|
|
482
|
+
return this.request(`/sessions/${this.sessionId}`, r => {
|
|
462
483
|
r.method = "PATCH";
|
|
463
484
|
r.headers = { Authorization: this.options.authorization, 'Content-Type': 'application/json' };
|
|
464
485
|
r.body = JSON.stringify(data);
|
|
@@ -704,6 +725,7 @@ export class LavalinkNode {
|
|
|
704
725
|
* ```
|
|
705
726
|
*/
|
|
706
727
|
reconnect(instaReconnect = false) {
|
|
728
|
+
this.NodeManager.emit("reconnectinprogress", this);
|
|
707
729
|
if (instaReconnect) {
|
|
708
730
|
if (this.reconnectAttempts >= this.options.retryAmount) {
|
|
709
731
|
const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
|
|
@@ -732,6 +754,29 @@ export class LavalinkNode {
|
|
|
732
754
|
}
|
|
733
755
|
/** @private util function for handling opening events from websocket */
|
|
734
756
|
async open() {
|
|
757
|
+
this.isAlive = true;
|
|
758
|
+
// trigger heartbeat-ping timeout - this is to check wether the client lost connection without knowing it
|
|
759
|
+
if (this.options.enablePingOnStatsCheck)
|
|
760
|
+
this.heartBeat();
|
|
761
|
+
if (this.heartBeatInterval)
|
|
762
|
+
clearInterval(this.heartBeatInterval);
|
|
763
|
+
if (this.options.heartBeatInterval > 0) {
|
|
764
|
+
// everytime a pong happens, set this.isAlive to true
|
|
765
|
+
this.socket.on("pong", () => {
|
|
766
|
+
this.heartBeatPongTimestamp = performance.now();
|
|
767
|
+
this.isAlive = true;
|
|
768
|
+
});
|
|
769
|
+
// every x ms send a ping to lavalink to retrieve a pong later on
|
|
770
|
+
this.heartBeatInterval = setInterval(() => {
|
|
771
|
+
if (!this.socket)
|
|
772
|
+
return console.error("Node-Heartbeat-Interval - Socket not available - maybe reconnecting?");
|
|
773
|
+
if (!this.isAlive)
|
|
774
|
+
this.close(500, "Node-Heartbeat-Timeout");
|
|
775
|
+
this.isAlive = false;
|
|
776
|
+
this.heartBeatPingTimestamp = performance.now();
|
|
777
|
+
this.socket.ping();
|
|
778
|
+
}, this.options.heartBeatInterval || 30000);
|
|
779
|
+
}
|
|
735
780
|
if (this.reconnectTimeout)
|
|
736
781
|
clearTimeout(this.reconnectTimeout);
|
|
737
782
|
// reset the reconnect attempts amount
|
|
@@ -745,6 +790,12 @@ export class LavalinkNode {
|
|
|
745
790
|
}
|
|
746
791
|
/** @private util function for handling closing events from websocket */
|
|
747
792
|
close(code, reason) {
|
|
793
|
+
if (this.pingTimeout)
|
|
794
|
+
clearTimeout(this.pingTimeout);
|
|
795
|
+
if (this.heartBeatInterval)
|
|
796
|
+
clearInterval(this.heartBeatInterval);
|
|
797
|
+
if (code === 1006 && !reason)
|
|
798
|
+
reason = "Socket got terminated due to no ping connection";
|
|
748
799
|
this.NodeManager.emit("disconnect", this, { code, reason });
|
|
749
800
|
if (code !== 1000 || reason !== "Node-Destroy")
|
|
750
801
|
this.reconnect();
|
|
@@ -754,6 +805,14 @@ export class LavalinkNode {
|
|
|
754
805
|
if (!error)
|
|
755
806
|
return;
|
|
756
807
|
this.NodeManager.emit("error", this, error);
|
|
808
|
+
if (this.options.closeOnError) {
|
|
809
|
+
if (this.heartBeatInterval)
|
|
810
|
+
clearInterval(this.heartBeatInterval);
|
|
811
|
+
if (this.pingTimeout)
|
|
812
|
+
clearTimeout(this.pingTimeout);
|
|
813
|
+
this.socket?.close(500, "Node-Error - Force Reconnect");
|
|
814
|
+
}
|
|
815
|
+
;
|
|
757
816
|
}
|
|
758
817
|
/** @private util function for handling message events from websocket */
|
|
759
818
|
async message(d) {
|
|
@@ -767,6 +826,8 @@ export class LavalinkNode {
|
|
|
767
826
|
this.NodeManager.emit("raw", this, payload);
|
|
768
827
|
switch (payload.op) {
|
|
769
828
|
case "stats":
|
|
829
|
+
if (this.options.enablePingOnStatsCheck)
|
|
830
|
+
this.heartBeat(); // lavalink doesn'T send "ping" periodically, therefore we use the stats message to check for a ping
|
|
770
831
|
delete payload.op;
|
|
771
832
|
this.stats = { ...payload };
|
|
772
833
|
break;
|
|
@@ -796,7 +857,13 @@ export class LavalinkNode {
|
|
|
796
857
|
this.sessionId = payload.sessionId;
|
|
797
858
|
this.resuming.enabled = payload.resumed;
|
|
798
859
|
if (payload.resumed === true) {
|
|
799
|
-
|
|
860
|
+
try {
|
|
861
|
+
this.NodeManager.emit("resumed", this, payload, await this.fetchAllPlayers());
|
|
862
|
+
}
|
|
863
|
+
catch (e) {
|
|
864
|
+
console.error("Failed to fetch players for resumed event, falling back without players array", e);
|
|
865
|
+
this.NodeManager.emit("resumed", this, payload, []);
|
|
866
|
+
}
|
|
800
867
|
}
|
|
801
868
|
break;
|
|
802
869
|
default:
|
|
@@ -806,7 +873,7 @@ export class LavalinkNode {
|
|
|
806
873
|
}
|
|
807
874
|
/** @private middleware util function for handling all kind of events from websocket */
|
|
808
875
|
async handleEvent(payload) {
|
|
809
|
-
if (!payload
|
|
876
|
+
if (!payload?.guildId)
|
|
810
877
|
return;
|
|
811
878
|
const player = this.NodeManager.LavalinkManager.getPlayer(payload.guildId);
|
|
812
879
|
if (!player)
|
|
@@ -845,39 +912,51 @@ export class LavalinkNode {
|
|
|
845
912
|
}
|
|
846
913
|
return;
|
|
847
914
|
}
|
|
915
|
+
async getTrackOfPayload(payload) {
|
|
916
|
+
return "track" in payload
|
|
917
|
+
? this.NodeManager.LavalinkManager.utils.buildTrack(payload.track, undefined)
|
|
918
|
+
: null;
|
|
919
|
+
}
|
|
848
920
|
/** @private util function for handling trackStart event */
|
|
849
|
-
trackStart(player, track, payload) {
|
|
921
|
+
async trackStart(player, track, payload) {
|
|
850
922
|
player.playing = true;
|
|
851
923
|
player.paused = false;
|
|
852
924
|
// don't emit the event if previous track == new track aka track loop
|
|
853
925
|
if (this.NodeManager.LavalinkManager.options?.emitNewSongsOnly === true && player.queue.previous[0]?.info?.identifier === track?.info?.identifier)
|
|
854
926
|
return;
|
|
855
|
-
|
|
927
|
+
if (!player.queue.current) {
|
|
928
|
+
player.queue.current = await this.getTrackOfPayload(payload);
|
|
929
|
+
if (player.queue.current)
|
|
930
|
+
await player.queue.utils.save();
|
|
931
|
+
}
|
|
932
|
+
return this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
|
|
856
933
|
}
|
|
857
934
|
/** @private util function for handling trackEnd event */
|
|
858
935
|
async trackEnd(player, track, payload) {
|
|
936
|
+
const trackToUse = track || await this.getTrackOfPayload(payload);
|
|
937
|
+
// If a track was forcibly played
|
|
938
|
+
if (payload.reason === "replaced") {
|
|
939
|
+
return this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
940
|
+
}
|
|
859
941
|
// If there are no songs in the queue
|
|
860
942
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
861
943
|
return this.queueEnd(player, track, payload);
|
|
862
|
-
// If a track was forcibly played
|
|
863
|
-
if (payload.reason === "replaced")
|
|
864
|
-
return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
865
944
|
// If a track had an error while starting
|
|
866
945
|
if (["loadFailed", "cleanup"].includes(payload.reason)) {
|
|
867
946
|
await queueTrackEnd(player);
|
|
868
947
|
// if no track available, end queue
|
|
869
948
|
if (!player.queue.current)
|
|
870
|
-
return this.queueEnd(player,
|
|
949
|
+
return this.queueEnd(player, trackToUse, payload);
|
|
871
950
|
// fire event
|
|
872
|
-
this.NodeManager.LavalinkManager.emit("trackEnd", player,
|
|
951
|
+
this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
873
952
|
// play track if autoSkip is true
|
|
874
953
|
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
875
954
|
}
|
|
876
955
|
// remove tracks from the queue
|
|
877
956
|
if (player.repeatMode !== "track" || player.get("internal_skipped"))
|
|
878
957
|
await queueTrackEnd(player);
|
|
879
|
-
else if (
|
|
880
|
-
player.queue.previous.unshift(
|
|
958
|
+
else if (trackToUse && !trackToUse?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
|
|
959
|
+
player.queue.previous.unshift(trackToUse);
|
|
881
960
|
if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
|
|
882
961
|
player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
|
|
883
962
|
await player.queue.utils.save();
|
|
@@ -885,60 +964,65 @@ export class LavalinkNode {
|
|
|
885
964
|
player.set("internal_skipped", false);
|
|
886
965
|
// if no track available, end queue
|
|
887
966
|
if (!player.queue.current)
|
|
888
|
-
return this.queueEnd(player,
|
|
967
|
+
return this.queueEnd(player, trackToUse, payload);
|
|
889
968
|
// fire event
|
|
890
|
-
this.NodeManager.LavalinkManager.emit("trackEnd", player,
|
|
969
|
+
this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
891
970
|
// play track if autoSkip is true
|
|
892
971
|
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
893
972
|
}
|
|
894
973
|
/** @private util function for handling trackStuck event */
|
|
895
974
|
async trackStuck(player, track, payload) {
|
|
896
|
-
this.NodeManager.LavalinkManager.emit("trackStuck", player, track, payload);
|
|
975
|
+
this.NodeManager.LavalinkManager.emit("trackStuck", player, track || await this.getTrackOfPayload(payload), payload);
|
|
897
976
|
// If there are no songs in the queue
|
|
898
977
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
899
|
-
return this.queueEnd(player, track, payload);
|
|
978
|
+
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
900
979
|
// remove the current track, and enqueue the next one
|
|
901
980
|
await queueTrackEnd(player);
|
|
902
981
|
// if no track available, end queue
|
|
903
982
|
if (!player.queue.current)
|
|
904
|
-
return this.queueEnd(player, track, payload);
|
|
983
|
+
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
905
984
|
// play track if autoSkip is true
|
|
906
985
|
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
907
986
|
}
|
|
908
987
|
/** @private util function for handling trackError event */
|
|
909
988
|
async trackError(player, track, payload) {
|
|
910
|
-
this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
|
|
989
|
+
this.NodeManager.LavalinkManager.emit("trackError", player, track || await this.getTrackOfPayload(payload), payload);
|
|
911
990
|
return; // get's handled by trackEnd
|
|
912
991
|
// If there are no songs in the queue
|
|
913
992
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
914
|
-
return this.queueEnd(player, track, payload);
|
|
993
|
+
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
915
994
|
// remove the current track, and enqueue the next one
|
|
916
995
|
await queueTrackEnd(player);
|
|
917
996
|
// if no track available, end queue
|
|
918
997
|
if (!player.queue.current)
|
|
919
|
-
return this.queueEnd(player, track, payload);
|
|
998
|
+
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
920
999
|
// play track if autoSkip is true
|
|
921
1000
|
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
922
1001
|
}
|
|
923
1002
|
/** @private util function for handling socketClosed event */
|
|
924
1003
|
socketClosed(player, payload) {
|
|
925
|
-
|
|
1004
|
+
this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
|
|
1005
|
+
// i don't think this is needed.
|
|
1006
|
+
// this.socket = null;
|
|
1007
|
+
// // causing a socket reconnect
|
|
1008
|
+
// this.connect();
|
|
1009
|
+
return;
|
|
926
1010
|
}
|
|
927
1011
|
/** @private util function for handling SponsorBlock Segmentloaded event */
|
|
928
|
-
SponsorBlockSegmentLoaded(player, track, payload) {
|
|
929
|
-
return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track, payload);
|
|
1012
|
+
async SponsorBlockSegmentLoaded(player, track, payload) {
|
|
1013
|
+
return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track || await this.getTrackOfPayload(payload), payload);
|
|
930
1014
|
}
|
|
931
1015
|
/** @private util function for handling SponsorBlock SegmentSkipped event */
|
|
932
|
-
SponsorBlockSegmentSkipped(player, track, payload) {
|
|
933
|
-
return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track, payload);
|
|
1016
|
+
async SponsorBlockSegmentSkipped(player, track, payload) {
|
|
1017
|
+
return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track || await this.getTrackOfPayload(payload), payload);
|
|
934
1018
|
}
|
|
935
1019
|
/** @private util function for handling SponsorBlock Chaptersloaded event */
|
|
936
|
-
SponsorBlockChaptersLoaded(player, track, payload) {
|
|
937
|
-
return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track, payload);
|
|
1020
|
+
async SponsorBlockChaptersLoaded(player, track, payload) {
|
|
1021
|
+
return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track || await this.getTrackOfPayload(payload), payload);
|
|
938
1022
|
}
|
|
939
1023
|
/** @private util function for handling SponsorBlock Chaptersstarted event */
|
|
940
|
-
SponsorBlockChapterStarted(player, track, payload) {
|
|
941
|
-
return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track, payload);
|
|
1024
|
+
async SponsorBlockChapterStarted(player, track, payload) {
|
|
1025
|
+
return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track || await this.getTrackOfPayload(payload), payload);
|
|
942
1026
|
}
|
|
943
1027
|
/**
|
|
944
1028
|
* Get the current sponsorblocks for the sponsorblock plugin
|
|
@@ -1025,7 +1109,12 @@ export class LavalinkNode {
|
|
|
1025
1109
|
}
|
|
1026
1110
|
}
|
|
1027
1111
|
player.set("internal_autoplayStopPlaying", undefined);
|
|
1028
|
-
|
|
1112
|
+
if (track && !track?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
|
|
1113
|
+
player.queue.previous.unshift(track);
|
|
1114
|
+
if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
|
|
1115
|
+
player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
|
|
1116
|
+
await player.queue.utils.save();
|
|
1117
|
+
}
|
|
1029
1118
|
if (payload?.reason !== "stopped") {
|
|
1030
1119
|
await player.queue.utils.save();
|
|
1031
1120
|
}
|