lavalink-client 2.2.0 → 2.2.2
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 +116 -15
- package/dist/cjs/structures/Filters.d.ts +1 -1
- package/dist/cjs/structures/Filters.js +9 -9
- package/dist/cjs/structures/LavalinkManager.d.ts +24 -7
- package/dist/cjs/structures/LavalinkManager.js +15 -2
- package/dist/cjs/structures/LavalinkManagerStatics.d.ts +3 -0
- package/dist/cjs/structures/LavalinkManagerStatics.js +4 -1
- package/dist/cjs/structures/Node.d.ts +307 -22
- package/dist/cjs/structures/Node.js +328 -72
- package/dist/cjs/structures/NodeManager.js +3 -1
- package/dist/cjs/structures/Player.d.ts +44 -8
- package/dist/cjs/structures/Player.js +27 -18
- package/dist/cjs/structures/Queue.d.ts +47 -0
- package/dist/cjs/structures/Queue.js +104 -1
- package/dist/cjs/structures/Track.d.ts +1 -0
- package/dist/cjs/structures/Utils.d.ts +3 -0
- package/dist/cjs/structures/Utils.js +6 -4
- package/dist/esm/structures/Filters.d.ts +1 -1
- package/dist/esm/structures/Filters.js +9 -9
- package/dist/esm/structures/LavalinkManager.d.ts +24 -7
- package/dist/esm/structures/LavalinkManager.js +15 -2
- package/dist/esm/structures/LavalinkManagerStatics.d.ts +3 -0
- package/dist/esm/structures/LavalinkManagerStatics.js +4 -1
- package/dist/esm/structures/Node.d.ts +307 -22
- package/dist/esm/structures/Node.js +328 -72
- package/dist/esm/structures/NodeManager.js +3 -1
- package/dist/esm/structures/Player.d.ts +44 -8
- package/dist/esm/structures/Player.js +27 -18
- package/dist/esm/structures/Queue.d.ts +47 -0
- package/dist/esm/structures/Queue.js +104 -1
- package/dist/esm/structures/Track.d.ts +1 -0
- package/dist/esm/structures/Utils.d.ts +3 -0
- package/dist/esm/structures/Utils.js +6 -4
- package/dist/types/structures/Filters.d.ts +1 -1
- package/dist/types/structures/LavalinkManager.d.ts +24 -7
- package/dist/types/structures/LavalinkManagerStatics.d.ts +3 -0
- package/dist/types/structures/Node.d.ts +307 -22
- package/dist/types/structures/Player.d.ts +44 -8
- package/dist/types/structures/Queue.d.ts +47 -0
- package/dist/types/structures/Track.d.ts +1 -0
- package/dist/types/structures/Utils.d.ts +3 -0
- package/package.json +2 -3
|
@@ -3,11 +3,15 @@ import WebSocket from "ws";
|
|
|
3
3
|
import { DestroyReasons } from "./Player";
|
|
4
4
|
import { NodeSymbol, queueTrackEnd } from "./Utils";
|
|
5
5
|
export const validSponsorBlocks = ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "filler"];
|
|
6
|
+
/**
|
|
7
|
+
* Lavalink Node creator class
|
|
8
|
+
*/
|
|
6
9
|
export class LavalinkNode {
|
|
7
10
|
/** The provided Options of the Node */
|
|
8
11
|
options;
|
|
9
12
|
/** The amount of rest calls the node has made. */
|
|
10
13
|
calls = 0;
|
|
14
|
+
/** Stats from lavalink, will be updated via an interval by lavalink. */
|
|
11
15
|
stats = {
|
|
12
16
|
players: 0,
|
|
13
17
|
playingPlayers: 0,
|
|
@@ -29,6 +33,7 @@ export class LavalinkNode {
|
|
|
29
33
|
sent: 0,
|
|
30
34
|
}
|
|
31
35
|
};
|
|
36
|
+
/** The current sessionId, only present when connected */
|
|
32
37
|
sessionId = null;
|
|
33
38
|
/** Wether the node resuming is enabled or not */
|
|
34
39
|
resuming = { enabled: true, timeout: null };
|
|
@@ -48,6 +53,14 @@ export class LavalinkNode {
|
|
|
48
53
|
* Create a new Node
|
|
49
54
|
* @param options Lavalink Node Options
|
|
50
55
|
* @param manager Node Manager
|
|
56
|
+
*
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* // don't create a node manually, instead use:
|
|
61
|
+
*
|
|
62
|
+
* client.lavalink.nodeManager.createNode(options)
|
|
63
|
+
* ```
|
|
51
64
|
*/
|
|
52
65
|
constructor(options, manager) {
|
|
53
66
|
this.options = {
|
|
@@ -64,11 +77,43 @@ export class LavalinkNode {
|
|
|
64
77
|
this.options.regions = (this.options.regions || []).map(a => a.toLowerCase());
|
|
65
78
|
Object.defineProperty(this, NodeSymbol, { configurable: true, value: true });
|
|
66
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse url params correctly for lavalink requests, including support for urls and uris.
|
|
82
|
+
* @param url input url object
|
|
83
|
+
* @param extraQueryUrlParams UrlSearchParams to use in a encodedURI, useful for example for flowertts
|
|
84
|
+
* @returns the url as a valid string
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* player.node.getRequestingUrl(new URL(`http://localhost:2333/v4/loadtracks?identifier=Never gonna give you up`));
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
getRequestingUrl(url, extraQueryUrlParams) {
|
|
92
|
+
if (!url.searchParams.size)
|
|
93
|
+
return `${url.origin}${url.pathname}`;
|
|
94
|
+
const keysToAdd = [];
|
|
95
|
+
for (const [paramKey, paramValue] of url.searchParams.entries()) {
|
|
96
|
+
const decoded = decodeURIComponent(paramValue).trim(); // double decoding, once internally, a second time if decoded by provided user.
|
|
97
|
+
if (decoded.includes("://") && !/^https?:\/\//.test(decoded)) { // uri, but not url.
|
|
98
|
+
const [key, ...values] = decoded.split("://");
|
|
99
|
+
keysToAdd.push(`${paramKey}=${encodeURI(`${key}://${encodeURIComponent(values.join("://"))}${extraQueryUrlParams && extraQueryUrlParams?.size > 0 ? `?${extraQueryUrlParams.toString()}` : ""}`)}`);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
keysToAdd.push(`${paramKey}=${encodeURIComponent(decoded)}`);
|
|
103
|
+
}
|
|
104
|
+
return `${url.origin}${url.pathname}?${keysToAdd.join("&")}`;
|
|
105
|
+
}
|
|
67
106
|
/**
|
|
68
107
|
* Raw Request util function
|
|
69
108
|
* @param endpoint endpoint string
|
|
70
109
|
* @param modify modify the request
|
|
71
|
-
* @
|
|
110
|
+
* @param extraQueryUrlParams UrlSearchParams to use in a encodedURI, useful for example for flowertts
|
|
111
|
+
* @returns object containing request and option information
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* player.node.rawRequest(`/loadtracks?identifier=Never gonna give you up`, (options) => options.method = "GET");
|
|
116
|
+
* ```
|
|
72
117
|
*/
|
|
73
118
|
async rawRequest(endpoint, modify) {
|
|
74
119
|
const options = {
|
|
@@ -82,16 +127,23 @@ export class LavalinkNode {
|
|
|
82
127
|
modify?.(options);
|
|
83
128
|
const url = new URL(`${this.restAddress}${options.path}`);
|
|
84
129
|
url.searchParams.append("trace", "true");
|
|
130
|
+
const urlToUse = this.getRequestingUrl(url, options?.extraQueryUrlParams);
|
|
85
131
|
delete options.path;
|
|
86
|
-
|
|
132
|
+
delete options.extraQueryUrlParams;
|
|
133
|
+
const request = await fetch(urlToUse, options);
|
|
87
134
|
this.calls++;
|
|
88
135
|
return { request, options };
|
|
89
136
|
}
|
|
90
137
|
/**
|
|
91
|
-
* Makes an API call to the Node
|
|
138
|
+
* Makes an API call to the Node. Should only be used for manual parsing like for not supported plugins
|
|
92
139
|
* @param endpoint The endpoint that we will make the call to
|
|
93
140
|
* @param modify Used to modify the request before being sent
|
|
94
141
|
* @returns The returned data
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* player.node.request(`/loadtracks?identifier=Never gonna give you up`, (options) => options.method = "GET", false);
|
|
146
|
+
* ```
|
|
95
147
|
*/
|
|
96
148
|
async request(endpoint, modify, parseAsText = false) {
|
|
97
149
|
const { request, options } = await this.rawRequest(endpoint, modify);
|
|
@@ -105,9 +157,17 @@ export class LavalinkNode {
|
|
|
105
157
|
* Search something raw on the node, please note only add tracks to players of that node
|
|
106
158
|
* @param query SearchQuery Object
|
|
107
159
|
* @param requestUser Request User for creating the player(s)
|
|
160
|
+
* @param throwOnEmpty Wether to throw on an empty result or not
|
|
108
161
|
* @returns Searchresult
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* // use player.search() instead
|
|
166
|
+
* player.node.search({ query: "Never gonna give you up by Rick Astley", source: "soundcloud" }, interaction.user);
|
|
167
|
+
* player.node.search({ query: "https://deezer.com/track/123456789" }, interaction.user);
|
|
168
|
+
* ```
|
|
109
169
|
*/
|
|
110
|
-
async search(query, requestUser) {
|
|
170
|
+
async search(query, requestUser, throwOnEmpty = false) {
|
|
111
171
|
const Query = this.NodeManager.LavalinkManager.utils.transformQuery(query);
|
|
112
172
|
this.NodeManager.LavalinkManager.utils.validateQueryString(this, Query.query, Query.source);
|
|
113
173
|
if (Query.source)
|
|
@@ -117,19 +177,25 @@ export class LavalinkNode {
|
|
|
117
177
|
}
|
|
118
178
|
let uri = `/loadtracks?identifier=`;
|
|
119
179
|
if (/^https?:\/\//.test(Query.query) || ["http", "https", "link", "uri"].includes(Query.source)) { // if it's a link simply encode it
|
|
120
|
-
uri += encodeURIComponent(
|
|
180
|
+
uri += encodeURIComponent(Query.query);
|
|
121
181
|
}
|
|
122
182
|
else { // if not make a query out of it
|
|
123
183
|
if (Query.source !== "local")
|
|
124
184
|
uri += `${Query.source}:`; // only add the query source string if it's not a local track
|
|
125
185
|
if (Query.source === "ftts")
|
|
126
|
-
uri += `//${encodeURIComponent(
|
|
186
|
+
uri += `//${encodeURIComponent(Query.query)}`;
|
|
127
187
|
else
|
|
128
|
-
uri += encodeURIComponent(
|
|
188
|
+
uri += encodeURIComponent(Query.query);
|
|
129
189
|
}
|
|
130
|
-
const res = await this.request(uri)
|
|
190
|
+
const res = await this.request(uri, (options) => {
|
|
191
|
+
if (typeof query === "object" && typeof query.extraQueryUrlParams?.size === "number" && query.extraQueryUrlParams?.size > 0) {
|
|
192
|
+
options.extraQueryUrlParams = query.extraQueryUrlParams;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
131
195
|
// transform the data which can be Error, Track or Track[] to enfore [Track]
|
|
132
196
|
const resTracks = res.loadType === "playlist" ? res.data?.tracks : res.loadType === "track" ? [res.data] : res.loadType === "search" ? Array.isArray(res.data) ? res.data : [res.data] : [];
|
|
197
|
+
if (throwOnEmpty === true && (res.loadType === "empty" || !resTracks.length))
|
|
198
|
+
throw new Error("Nothing found");
|
|
133
199
|
return {
|
|
134
200
|
loadType: res.loadType,
|
|
135
201
|
exception: res.loadType === "error" ? res.data : null,
|
|
@@ -146,6 +212,19 @@ export class LavalinkNode {
|
|
|
146
212
|
tracks: (resTracks.length ? resTracks.map(t => this.NodeManager.LavalinkManager.utils.buildTrack(t, requestUser)) : [])
|
|
147
213
|
};
|
|
148
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Search something using the lavaSearchPlugin (filtered searches by types)
|
|
217
|
+
* @param query LavaSearchQuery Object
|
|
218
|
+
* @param requestUser Request User for creating the player(s)
|
|
219
|
+
* @param throwOnEmpty Wether to throw on an empty result or not
|
|
220
|
+
* @returns LavaSearchresult
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* // use player.search() instead
|
|
225
|
+
* player.node.lavaSearch({ types: ["playlist", "album"], query: "Rick Astley", source: "spotify" }, interaction.user);
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
149
228
|
async lavaSearch(query, requestUser, throwOnEmpty = false) {
|
|
150
229
|
const Query = this.NodeManager.LavalinkManager.utils.transformLavaSearchQuery(query);
|
|
151
230
|
if (Query.source)
|
|
@@ -159,9 +238,9 @@ export class LavalinkNode {
|
|
|
159
238
|
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin"))
|
|
160
239
|
throw new RangeError(`there is no lavasrc-plugin available in the lavalink node: ${this.id}`);
|
|
161
240
|
const { request } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
|
|
162
|
-
if (throwOnEmpty === true)
|
|
163
|
-
throw new Error("Nothing found");
|
|
164
241
|
const res = (request.status === 204 ? {} : await request.json());
|
|
242
|
+
if (throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length)
|
|
243
|
+
throw new Error("Nothing found");
|
|
165
244
|
return {
|
|
166
245
|
tracks: res.tracks?.map(v => this.NodeManager.LavalinkManager.utils.buildTrack(v, requestUser)) || [],
|
|
167
246
|
albums: res.albums?.map(v => ({ info: v.info, pluginInfo: v?.plugin || v.pluginInfo, tracks: v.tracks.map(v => this.NodeManager.LavalinkManager.utils.buildTrack(v, requestUser)) })) || [],
|
|
@@ -173,8 +252,14 @@ export class LavalinkNode {
|
|
|
173
252
|
}
|
|
174
253
|
/**
|
|
175
254
|
* Update the Player State on the Lavalink Server
|
|
176
|
-
* @param data
|
|
177
|
-
* @returns
|
|
255
|
+
* @param data data to send to lavalink and sync locally
|
|
256
|
+
* @returns result from lavalink
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* // use player.search() instead
|
|
261
|
+
* player.node.updatePlayer({ guildId: player.guildId, playerOptions: { paused: true } }); // example to pause it
|
|
262
|
+
* ```
|
|
178
263
|
*/
|
|
179
264
|
async updatePlayer(data) {
|
|
180
265
|
if (!this.sessionId)
|
|
@@ -196,7 +281,13 @@ export class LavalinkNode {
|
|
|
196
281
|
/**
|
|
197
282
|
* Destroys the Player on the Lavalink Server
|
|
198
283
|
* @param guildId
|
|
199
|
-
* @returns
|
|
284
|
+
* @returns request result
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* // use player.destroy() instead
|
|
289
|
+
* player.node.destroyPlayer(player.guildId);
|
|
290
|
+
* ```
|
|
200
291
|
*/
|
|
201
292
|
async destroyPlayer(guildId) {
|
|
202
293
|
if (!this.sessionId)
|
|
@@ -206,7 +297,15 @@ export class LavalinkNode {
|
|
|
206
297
|
/**
|
|
207
298
|
* Connect to the Lavalink Node
|
|
208
299
|
* @param sessionId Provide the Session Id of the previous connection, to resume the node and it's player(s)
|
|
209
|
-
* @returns
|
|
300
|
+
* @returns void
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```ts
|
|
304
|
+
* player.node.connect(); // if provided on bootup in managerOptions#nodes, this will be called automatically when doing lavalink.init()
|
|
305
|
+
*
|
|
306
|
+
* // or connect from a resuming session:
|
|
307
|
+
* player.node.connect("sessionId");
|
|
308
|
+
* ```
|
|
210
309
|
*/
|
|
211
310
|
connect(sessionId) {
|
|
212
311
|
if (this.connected)
|
|
@@ -226,20 +325,37 @@ export class LavalinkNode {
|
|
|
226
325
|
this.socket.on("message", this.message.bind(this));
|
|
227
326
|
this.socket.on("error", this.error.bind(this));
|
|
228
327
|
}
|
|
229
|
-
/**
|
|
328
|
+
/**
|
|
329
|
+
* Get the id of the node
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```ts
|
|
333
|
+
* const nodeId = player.node.id;
|
|
334
|
+
* console.log("node id is: ", nodeId)
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
230
337
|
get id() {
|
|
231
338
|
return this.options.id || `${this.options.host}:${this.options.port}`;
|
|
232
339
|
}
|
|
233
340
|
/**
|
|
234
341
|
* Destroys the Node-Connection (Websocket) and all player's of the node
|
|
235
|
-
* @
|
|
342
|
+
* @param destroyReason Destroyreason to use when destroying the players
|
|
343
|
+
* @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
|
|
344
|
+
* @returns void
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```ts
|
|
348
|
+
* player.node.destroy("custom Player Destroy Reason", true);
|
|
349
|
+
* ```
|
|
236
350
|
*/
|
|
237
351
|
destroy(destroyReason, deleteNode = true) {
|
|
238
352
|
if (!this.connected)
|
|
239
353
|
return;
|
|
240
|
-
const players = this.NodeManager.LavalinkManager.players.filter(p => p.node.id
|
|
354
|
+
const players = this.NodeManager.LavalinkManager.players.filter(p => p.node.id === this.id);
|
|
241
355
|
if (players)
|
|
242
|
-
players.forEach(p =>
|
|
356
|
+
players.forEach(p => {
|
|
357
|
+
p.destroy(destroyReason || DestroyReasons.NodeDestroy);
|
|
358
|
+
});
|
|
243
359
|
this.socket.close(1000, "Node-Destroy");
|
|
244
360
|
this.socket.removeAllListeners();
|
|
245
361
|
this.socket = null;
|
|
@@ -254,14 +370,47 @@ export class LavalinkNode {
|
|
|
254
370
|
}
|
|
255
371
|
return;
|
|
256
372
|
}
|
|
257
|
-
/**
|
|
373
|
+
/**
|
|
374
|
+
* Returns if connected to the Node.
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```ts
|
|
378
|
+
* const isConnected = player.node.connected;
|
|
379
|
+
* console.log("node is connected: ", isConnected ? "yes" : "no")
|
|
380
|
+
* ```
|
|
381
|
+
*/
|
|
258
382
|
get connected() {
|
|
259
383
|
if (!this.socket)
|
|
260
384
|
return false;
|
|
261
385
|
return this.socket.readyState === WebSocket.OPEN;
|
|
262
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Returns the current ConnectionStatus
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```ts
|
|
392
|
+
* try {
|
|
393
|
+
* const statusOfConnection = player.node.connectionStatus;
|
|
394
|
+
* console.log("node's connection status is:", statusOfConnection)
|
|
395
|
+
* } catch (error) {
|
|
396
|
+
* console.error("no socket available?", error)
|
|
397
|
+
* }
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
get connectionStatus() {
|
|
401
|
+
if (!this.socket)
|
|
402
|
+
throw new Error("no websocket was initialized yet");
|
|
403
|
+
return ["CONNECTING", "OPEN", "CLOSING", "CLOSED"][this.socket.readyState] || "UNKNOWN";
|
|
404
|
+
}
|
|
263
405
|
/**
|
|
264
406
|
* Gets all Players of a Node
|
|
407
|
+
* @returns array of players inside of lavalink
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```ts
|
|
411
|
+
* const node = lavalink.nodes.get("NODEID");
|
|
412
|
+
* const playersOfLavalink = await node?.fetchAllPlayers();
|
|
413
|
+
* ```
|
|
265
414
|
*/
|
|
266
415
|
async fetchAllPlayers() {
|
|
267
416
|
if (!this.sessionId)
|
|
@@ -274,6 +423,13 @@ export class LavalinkNode {
|
|
|
274
423
|
}
|
|
275
424
|
/**
|
|
276
425
|
* Gets specific Player Information
|
|
426
|
+
* @returns lavalink player object if player exists on lavalink
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```ts
|
|
430
|
+
* const node = lavalink.nodes.get("NODEID");
|
|
431
|
+
* const playerInformation = await node?.fetchPlayer("guildId");
|
|
432
|
+
* ```
|
|
277
433
|
*/
|
|
278
434
|
async fetchPlayer(guildId) {
|
|
279
435
|
if (!this.sessionId)
|
|
@@ -284,6 +440,13 @@ export class LavalinkNode {
|
|
|
284
440
|
* Updates the session with and enables/disables resuming and timeout
|
|
285
441
|
* @param resuming Whether resuming is enabled for this session or not
|
|
286
442
|
* @param timeout The timeout in seconds (default is 60s)
|
|
443
|
+
* @returns the result of the request
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* ```ts
|
|
447
|
+
* const node = player.node || lavalink.nodes.get("NODEID");
|
|
448
|
+
* await node?.updateSession(true, 180e3); // will enable resuming for 180seconds
|
|
449
|
+
* ```
|
|
287
450
|
*/
|
|
288
451
|
async updateSession(resuming, timeout) {
|
|
289
452
|
if (!this.sessionId)
|
|
@@ -308,20 +471,35 @@ export class LavalinkNode {
|
|
|
308
471
|
*/
|
|
309
472
|
decode = {
|
|
310
473
|
/**
|
|
311
|
-
* Decode a single track into its info
|
|
312
|
-
* @param encoded
|
|
313
|
-
* @
|
|
474
|
+
* Decode a single track into its info
|
|
475
|
+
* @param encoded valid encoded base64 string from a track
|
|
476
|
+
* @param requester the requesteruser for building the track
|
|
477
|
+
* @returns decoded track from lavalink
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```ts
|
|
481
|
+
* const encodedBase64 = 'QAACDgMACk5vIERpZ2dpdHkAC0JsYWNrc3RyZWV0AAAAAAAEo4AABjkxNjQ5NgABAB9odHRwczovL2RlZXplci5jb20vdHJhY2svOTE2NDk2AQBpaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvY292ZXIvZGFlN2EyNjViNzlmYjcxMjc4Y2RlMjUwNDg0OWQ2ZjcvMTAwMHgxMDAwLTAwMDAwMC04MC0wLTAuanBnAQAMVVNJUjE5NjAwOTc4AAZkZWV6ZXIBAChObyBEaWdnaXR5OiBUaGUgVmVyeSBCZXN0IE9mIEJsYWNrc3RyZWV0AQAjaHR0cHM6Ly93d3cuZGVlemVyLmNvbS9hbGJ1bS8xMDMyNTQBACJodHRwczovL3d3dy5kZWV6ZXIuY29tL2FydGlzdC8xODYxAQBqaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvYXJ0aXN0L2YxNmNhYzM2ZmVjMzkxZjczN2I3ZDQ4MmY1YWM3M2UzLzEwMDB4MTAwMC0wMDAwMDAtODAtMC0wLmpwZwEAT2h0dHBzOi8vY2RuLXByZXZpZXctYS5kemNkbi5uZXQvc3RyZWFtL2MtYTE1Yjg1NzFhYTYyMDBjMDQ0YmY1OWM3NmVkOTEyN2MtNi5tcDMAAAAAAAAAAAA=';
|
|
482
|
+
* const track = await player.node.decode.singleTrack(encodedBase64, interaction.user);
|
|
483
|
+
* ```
|
|
314
484
|
*/
|
|
315
485
|
singleTrack: async (encoded, requester) => {
|
|
316
486
|
if (!encoded)
|
|
317
487
|
throw new SyntaxError("No encoded (Base64 string) was provided");
|
|
318
488
|
// return the decoded + builded track
|
|
319
|
-
return this.NodeManager.LavalinkManager.utils
|
|
489
|
+
return this.NodeManager.LavalinkManager.utils?.buildTrack(await this.request(`/decodetrack?encodedTrack=${encodeURIComponent(encoded.replace(/\s/g, ""))}`), requester);
|
|
320
490
|
},
|
|
321
491
|
/**
|
|
492
|
+
* Decodes multiple tracks into their info
|
|
493
|
+
* @param encodeds valid encoded base64 string array from all tracks
|
|
494
|
+
* @param requester the requesteruser for building the tracks
|
|
495
|
+
* @returns array of all tracks you decoded
|
|
322
496
|
*
|
|
323
|
-
* @
|
|
324
|
-
*
|
|
497
|
+
* @example
|
|
498
|
+
* ```ts
|
|
499
|
+
* const encodedBase64_1 = 'QAACDgMACk5vIERpZ2dpdHkAC0JsYWNrc3RyZWV0AAAAAAAEo4AABjkxNjQ5NgABAB9odHRwczovL2RlZXplci5jb20vdHJhY2svOTE2NDk2AQBpaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvY292ZXIvZGFlN2EyNjViNzlmYjcxMjc4Y2RlMjUwNDg0OWQ2ZjcvMTAwMHgxMDAwLTAwMDAwMC04MC0wLTAuanBnAQAMVVNJUjE5NjAwOTc4AAZkZWV6ZXIBAChObyBEaWdnaXR5OiBUaGUgVmVyeSBCZXN0IE9mIEJsYWNrc3RyZWV0AQAjaHR0cHM6Ly93d3cuZGVlemVyLmNvbS9hbGJ1bS8xMDMyNTQBACJodHRwczovL3d3dy5kZWV6ZXIuY29tL2FydGlzdC8xODYxAQBqaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvYXJ0aXN0L2YxNmNhYzM2ZmVjMzkxZjczN2I3ZDQ4MmY1YWM3M2UzLzEwMDB4MTAwMC0wMDAwMDAtODAtMC0wLmpwZwEAT2h0dHBzOi8vY2RuLXByZXZpZXctYS5kemNkbi5uZXQvc3RyZWFtL2MtYTE1Yjg1NzFhYTYyMDBjMDQ0YmY1OWM3NmVkOTEyN2MtNi5tcDMAAAAAAAAAAAA=';
|
|
500
|
+
* const encodedBase64_2 = 'QAABJAMAClRhbGsgYSBMb3QACjQwNHZpbmNlbnQAAAAAAAHr1gBxTzpodHRwczovL2FwaS12Mi5zb3VuZGNsb3VkLmNvbS9tZWRpYS9zb3VuZGNsb3VkOnRyYWNrczo4NTE0MjEwNzYvMzUyYTRiOTAtNzYxOS00M2E5LWJiOGItMjIxMzE0YzFjNjNhL3N0cmVhbS9obHMAAQAsaHR0cHM6Ly9zb3VuZGNsb3VkLmNvbS80MDR2aW5jZW50L3RhbGstYS1sb3QBADpodHRwczovL2kxLnNuZGNkbi5jb20vYXJ0d29ya3MtRTN1ek5Gc0Y4QzBXLTAtb3JpZ2luYWwuanBnAQAMUVpITkExOTg1Nzg0AApzb3VuZGNsb3VkAAAAAAAAAAA=';
|
|
501
|
+
* const tracks = await player.node.decode.multipleTracks([encodedBase64_1, encodedBase64_2], interaction.user);
|
|
502
|
+
* ```
|
|
325
503
|
*/
|
|
326
504
|
multipleTracks: async (encodeds, requester) => {
|
|
327
505
|
if (!Array.isArray(encodeds) || !encodeds.every(v => typeof v === "string" && v.length > 1))
|
|
@@ -337,14 +515,24 @@ export class LavalinkNode {
|
|
|
337
515
|
};
|
|
338
516
|
/**
|
|
339
517
|
* Request Lavalink statistics.
|
|
340
|
-
* @returns
|
|
518
|
+
* @returns the lavalink node stats
|
|
519
|
+
*
|
|
520
|
+
* @example
|
|
521
|
+
* ```ts
|
|
522
|
+
* const lavalinkStats = await player.node.fetchStats();
|
|
523
|
+
* ```
|
|
341
524
|
*/
|
|
342
525
|
async fetchStats() {
|
|
343
526
|
return await this.request(`/stats`);
|
|
344
527
|
}
|
|
345
528
|
/**
|
|
346
529
|
* Request Lavalink version.
|
|
347
|
-
* @returns
|
|
530
|
+
* @returns the current used lavalink version
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```ts
|
|
534
|
+
* const lavalinkVersion = await player.node.fetchVersion();
|
|
535
|
+
* ```
|
|
348
536
|
*/
|
|
349
537
|
async fetchVersion() {
|
|
350
538
|
// need to adjust path for no-prefix version info
|
|
@@ -352,7 +540,14 @@ export class LavalinkNode {
|
|
|
352
540
|
}
|
|
353
541
|
/**
|
|
354
542
|
* Request Lavalink information.
|
|
355
|
-
* @returns
|
|
543
|
+
* @returns lavalink info object
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* ```ts
|
|
547
|
+
* const lavalinkInfo = await player.node.fetchInfo();
|
|
548
|
+
* const availablePlugins:string[] = lavalinkInfo.plugins.map(plugin => plugin.name);
|
|
549
|
+
* const availableSources:string[] = lavalinkInfo.sourceManagers;
|
|
550
|
+
* ```
|
|
356
551
|
*/
|
|
357
552
|
async fetchInfo() {
|
|
358
553
|
return await this.request(`/info`);
|
|
@@ -362,7 +557,15 @@ export class LavalinkNode {
|
|
|
362
557
|
*/
|
|
363
558
|
routePlannerApi = {
|
|
364
559
|
/**
|
|
365
|
-
* Get routplanner Info from Lavalink
|
|
560
|
+
* Get routplanner Info from Lavalink for ip rotation
|
|
561
|
+
* @returns the status of the routeplanner
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* ```ts
|
|
565
|
+
* const routePlannerStatus = await player.node.routePlannerApi.getStatus();
|
|
566
|
+
* const usedBlock = routePlannerStatus.details?.ipBlock;
|
|
567
|
+
* const currentIp = routePlannerStatus.currentAddress;
|
|
568
|
+
* ```
|
|
366
569
|
*/
|
|
367
570
|
getStatus: async () => {
|
|
368
571
|
if (!this.sessionId)
|
|
@@ -370,8 +573,14 @@ export class LavalinkNode {
|
|
|
370
573
|
return await this.request(`/routeplanner/status`);
|
|
371
574
|
},
|
|
372
575
|
/**
|
|
373
|
-
* Release blacklisted IP address into pool of IPs
|
|
576
|
+
* Release blacklisted IP address into pool of IPs for ip rotation
|
|
374
577
|
* @param address IP address
|
|
578
|
+
* @returns request data of the request
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* ```ts
|
|
582
|
+
* await player.node.routePlannerApi.unmarkFailedAddress("ipv6address");
|
|
583
|
+
* ```
|
|
375
584
|
*/
|
|
376
585
|
unmarkFailedAddress: async (address) => {
|
|
377
586
|
if (!this.sessionId)
|
|
@@ -385,6 +594,12 @@ export class LavalinkNode {
|
|
|
385
594
|
},
|
|
386
595
|
/**
|
|
387
596
|
* Release all blacklisted IP addresses into pool of IPs
|
|
597
|
+
* @returns request data of the request
|
|
598
|
+
*
|
|
599
|
+
* @example
|
|
600
|
+
* ```ts
|
|
601
|
+
* await player.node.routePlannerApi.unmarkAllFailedAddresses();
|
|
602
|
+
* ```
|
|
388
603
|
*/
|
|
389
604
|
unmarkAllFailedAddresses: async () => {
|
|
390
605
|
if (!this.sessionId)
|
|
@@ -396,7 +611,7 @@ export class LavalinkNode {
|
|
|
396
611
|
});
|
|
397
612
|
}
|
|
398
613
|
};
|
|
399
|
-
/**
|
|
614
|
+
/** @private Utils for validating the */
|
|
400
615
|
validate() {
|
|
401
616
|
if (!this.options.authorization)
|
|
402
617
|
throw new SyntaxError("LavalinkNode requires 'authorization'");
|
|
@@ -405,6 +620,12 @@ export class LavalinkNode {
|
|
|
405
620
|
if (!this.options.port)
|
|
406
621
|
throw new SyntaxError("LavalinkNode requires 'port'");
|
|
407
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Sync the data of the player you make an action to lavalink to
|
|
625
|
+
* @param data data to use to update the player
|
|
626
|
+
* @param res result data from lavalink, to override, if available
|
|
627
|
+
* @returns boolean
|
|
628
|
+
*/
|
|
408
629
|
syncPlayerData(data, res) {
|
|
409
630
|
if (typeof data === "object" && typeof data?.guildId === "string" && typeof data.playerOptions === "object" && Object.keys(data.playerOptions).length > 1) {
|
|
410
631
|
const player = this.NodeManager.LavalinkManager.getPlayer(data.guildId);
|
|
@@ -415,8 +636,9 @@ export class LavalinkNode {
|
|
|
415
636
|
player.playing = !data.playerOptions.paused;
|
|
416
637
|
}
|
|
417
638
|
if (typeof data.playerOptions.position === "number") {
|
|
418
|
-
player.position = data.playerOptions.position;
|
|
639
|
+
// player.position = data.playerOptions.position;
|
|
419
640
|
player.lastPosition = data.playerOptions.position;
|
|
641
|
+
player.lastPositionChange = Date.now();
|
|
420
642
|
}
|
|
421
643
|
if (typeof data.playerOptions.voice !== "undefined")
|
|
422
644
|
player.voice = data.playerOptions.voice;
|
|
@@ -467,9 +689,22 @@ export class LavalinkNode {
|
|
|
467
689
|
}
|
|
468
690
|
return true;
|
|
469
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Get the rest Adress for making requests
|
|
694
|
+
*/
|
|
470
695
|
get restAddress() {
|
|
471
696
|
return `http${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}`;
|
|
472
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* Reconnect to the lavalink node
|
|
700
|
+
* @param instaReconnect @default false wether to instantly try to reconnect
|
|
701
|
+
* @returns void
|
|
702
|
+
*
|
|
703
|
+
* @example
|
|
704
|
+
* ```ts
|
|
705
|
+
* await player.node.reconnect();
|
|
706
|
+
* ```
|
|
707
|
+
*/
|
|
473
708
|
reconnect(instaReconnect = false) {
|
|
474
709
|
if (instaReconnect) {
|
|
475
710
|
if (this.reconnectAttempts >= this.options.retryAmount) {
|
|
@@ -497,6 +732,7 @@ export class LavalinkNode {
|
|
|
497
732
|
this.reconnectAttempts++;
|
|
498
733
|
}, this.options.retryDelay || 1000);
|
|
499
734
|
}
|
|
735
|
+
/** @private util function for handling opening events from websocket */
|
|
500
736
|
async open() {
|
|
501
737
|
if (this.reconnectTimeout)
|
|
502
738
|
clearTimeout(this.reconnectTimeout);
|
|
@@ -509,16 +745,19 @@ export class LavalinkNode {
|
|
|
509
745
|
}
|
|
510
746
|
this.NodeManager.emit("connect", this);
|
|
511
747
|
}
|
|
748
|
+
/** @private util function for handling closing events from websocket */
|
|
512
749
|
close(code, reason) {
|
|
513
750
|
this.NodeManager.emit("disconnect", this, { code, reason });
|
|
514
751
|
if (code !== 1000 || reason !== "Node-Destroy")
|
|
515
752
|
this.reconnect();
|
|
516
753
|
}
|
|
754
|
+
/** @private util function for handling error events from websocket */
|
|
517
755
|
error(error) {
|
|
518
756
|
if (!error)
|
|
519
757
|
return;
|
|
520
758
|
this.NodeManager.emit("error", this, error);
|
|
521
759
|
}
|
|
760
|
+
/** @private util function for handling message events from websocket */
|
|
522
761
|
async message(d) {
|
|
523
762
|
if (Array.isArray(d))
|
|
524
763
|
d = Buffer.concat(d);
|
|
@@ -539,42 +778,15 @@ export class LavalinkNode {
|
|
|
539
778
|
if (!player)
|
|
540
779
|
return;
|
|
541
780
|
const oldPlayer = player?.toJSON();
|
|
542
|
-
|
|
543
|
-
clearInterval(player.get("internal_updateInterval"));
|
|
544
|
-
// override the position
|
|
545
|
-
player.position = payload.state.position || 0;
|
|
781
|
+
player.lastPositionChange = Date.now();
|
|
546
782
|
player.lastPosition = payload.state.position || 0;
|
|
547
783
|
player.connected = payload.state.connected;
|
|
548
784
|
player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
|
|
549
785
|
if (!player.createdTimeStamp && payload.state.time)
|
|
550
786
|
player.createdTimeStamp = payload.state.time;
|
|
551
|
-
if (
|
|
552
|
-
player.
|
|
553
|
-
|
|
554
|
-
if (player.filterManager.filterUpdatedState >= 1) {
|
|
555
|
-
player.filterManager.filterUpdatedState++;
|
|
556
|
-
const maxMins = 8;
|
|
557
|
-
const currentDuration = player.queue.current?.info?.duration || 0;
|
|
558
|
-
if (currentDuration <= maxMins * 6e4 || isAbsolute(player.queue.current?.info?.uri)) {
|
|
559
|
-
if (player.filterManager.filterUpdatedState >= ((this.NodeManager.LavalinkManager.options.playerOptions.clientBasedPositionUpdateInterval || 250) > 400 ? 2 : 3)) {
|
|
560
|
-
player.filterManager.filterUpdatedState = 0;
|
|
561
|
-
player.seek(player.position);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
player.filterManager.filterUpdatedState = 0;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}, this.NodeManager.LavalinkManager.options.playerOptions.clientBasedPositionUpdateInterval || 250));
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
if (player.filterManager.filterUpdatedState >= 1) { // if no interval but instafix available, findable via the "filterUpdatedState" property
|
|
572
|
-
const maxMins = 8;
|
|
573
|
-
const currentDuration = player.queue.current?.info?.duration || 0;
|
|
574
|
-
if (currentDuration <= maxMins * 6e4 || isAbsolute(player.queue.current?.info?.uri))
|
|
575
|
-
player.seek(player.position);
|
|
576
|
-
player.filterManager.filterUpdatedState = 0;
|
|
577
|
-
}
|
|
787
|
+
if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600000) || isAbsolute(player.queue.current?.info?.uri))) {
|
|
788
|
+
player.filterManager.filterUpdatedState = false;
|
|
789
|
+
await player.seek(player.position);
|
|
578
790
|
}
|
|
579
791
|
this.NodeManager.LavalinkManager.emit("playerUpdate", oldPlayer, player);
|
|
580
792
|
}
|
|
@@ -594,7 +806,7 @@ export class LavalinkNode {
|
|
|
594
806
|
return;
|
|
595
807
|
}
|
|
596
808
|
}
|
|
597
|
-
|
|
809
|
+
/** @private middleware util function for handling all kind of events from websocket */
|
|
598
810
|
async handleEvent(payload) {
|
|
599
811
|
if (!payload.guildId)
|
|
600
812
|
return;
|
|
@@ -621,7 +833,7 @@ export class LavalinkNode {
|
|
|
621
833
|
this.SponsorBlockSegmentLoaded(player, player.queue.current, payload);
|
|
622
834
|
break;
|
|
623
835
|
case "SegmentSkipped":
|
|
624
|
-
this.
|
|
836
|
+
this.SponsorBlockSegmentSkipped(player, player.queue.current, payload);
|
|
625
837
|
break;
|
|
626
838
|
case "ChaptersLoaded":
|
|
627
839
|
this.SponsorBlockChaptersLoaded(player, player.queue.current, payload);
|
|
@@ -635,7 +847,7 @@ export class LavalinkNode {
|
|
|
635
847
|
}
|
|
636
848
|
return;
|
|
637
849
|
}
|
|
638
|
-
|
|
850
|
+
/** @private util function for handling trackStart event */
|
|
639
851
|
trackStart(player, track, payload) {
|
|
640
852
|
player.playing = true;
|
|
641
853
|
player.paused = false;
|
|
@@ -644,6 +856,7 @@ export class LavalinkNode {
|
|
|
644
856
|
return;
|
|
645
857
|
return this.NodeManager.LavalinkManager.emit("trackStart", player, track, payload);
|
|
646
858
|
}
|
|
859
|
+
/** @private util function for handling trackEnd event */
|
|
647
860
|
async trackEnd(player, track, payload) {
|
|
648
861
|
// If there are no songs in the queue
|
|
649
862
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
@@ -665,7 +878,7 @@ export class LavalinkNode {
|
|
|
665
878
|
// remove tracks from the queue
|
|
666
879
|
if (player.repeatMode !== "track" || player.get("internal_skipped"))
|
|
667
880
|
await queueTrackEnd(player);
|
|
668
|
-
else if (player.queue.current) { // If there was a current Track already and repeatmode === true, add it to the queue.
|
|
881
|
+
else if (player.queue.current && !player.queue.current?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
|
|
669
882
|
player.queue.previous.unshift(player.queue.current);
|
|
670
883
|
if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
|
|
671
884
|
player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
|
|
@@ -680,6 +893,7 @@ export class LavalinkNode {
|
|
|
680
893
|
// play track if autoSkip is true
|
|
681
894
|
return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
|
|
682
895
|
}
|
|
896
|
+
/** @private util function for handling trackStuck event */
|
|
683
897
|
async trackStuck(player, track, payload) {
|
|
684
898
|
this.NodeManager.LavalinkManager.emit("trackStuck", player, track, payload);
|
|
685
899
|
// If there are no songs in the queue
|
|
@@ -693,6 +907,7 @@ export class LavalinkNode {
|
|
|
693
907
|
// play track if autoSkip is true
|
|
694
908
|
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
695
909
|
}
|
|
910
|
+
/** @private util function for handling trackError event */
|
|
696
911
|
async trackError(player, track, payload) {
|
|
697
912
|
this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
|
|
698
913
|
return; // get's handled by trackEnd
|
|
@@ -707,23 +922,37 @@ export class LavalinkNode {
|
|
|
707
922
|
// play track if autoSkip is true
|
|
708
923
|
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
709
924
|
}
|
|
925
|
+
/** @private util function for handling socketClosed event */
|
|
710
926
|
socketClosed(player, payload) {
|
|
711
927
|
return this.NodeManager.LavalinkManager.emit("playerSocketClosed", player, payload);
|
|
712
928
|
}
|
|
713
|
-
|
|
929
|
+
/** @private util function for handling SponsorBlock Segmentloaded event */
|
|
714
930
|
SponsorBlockSegmentLoaded(player, track, payload) {
|
|
715
931
|
return this.NodeManager.LavalinkManager.emit("SegmentsLoaded", player, track, payload);
|
|
716
932
|
}
|
|
717
|
-
|
|
933
|
+
/** @private util function for handling SponsorBlock SegmentSkipped event */
|
|
934
|
+
SponsorBlockSegmentSkipped(player, track, payload) {
|
|
718
935
|
return this.NodeManager.LavalinkManager.emit("SegmentSkipped", player, track, payload);
|
|
719
936
|
}
|
|
937
|
+
/** @private util function for handling SponsorBlock Chaptersloaded event */
|
|
720
938
|
SponsorBlockChaptersLoaded(player, track, payload) {
|
|
721
939
|
return this.NodeManager.LavalinkManager.emit("ChaptersLoaded", player, track, payload);
|
|
722
940
|
}
|
|
941
|
+
/** @private util function for handling SponsorBlock Chaptersstarted event */
|
|
723
942
|
SponsorBlockChapterStarted(player, track, payload) {
|
|
724
943
|
return this.NodeManager.LavalinkManager.emit("ChapterStarted", player, track, payload);
|
|
725
944
|
}
|
|
726
|
-
|
|
945
|
+
/**
|
|
946
|
+
* Get the current sponsorblocks for the sponsorblock plugin
|
|
947
|
+
* @param player passthrough the player
|
|
948
|
+
* @returns sponsorblock seggment from lavalink
|
|
949
|
+
*
|
|
950
|
+
* @example
|
|
951
|
+
* ```ts
|
|
952
|
+
* // use it on the player via player.getSponsorBlock();
|
|
953
|
+
* const sponsorBlockSegments = await player.node.getSponsorBlock(player);
|
|
954
|
+
* ```
|
|
955
|
+
*/
|
|
727
956
|
async getSponsorBlock(player) {
|
|
728
957
|
// no plugin enabled
|
|
729
958
|
if (!this.info.plugins.find(v => v.name === "sponsorblock-plugin"))
|
|
@@ -731,6 +960,17 @@ export class LavalinkNode {
|
|
|
731
960
|
// do the request
|
|
732
961
|
return await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`);
|
|
733
962
|
}
|
|
963
|
+
/**
|
|
964
|
+
* Set the current sponsorblocks for the sponsorblock plugin
|
|
965
|
+
* @param player passthrough the player
|
|
966
|
+
* @returns void
|
|
967
|
+
*
|
|
968
|
+
* @example
|
|
969
|
+
* ```ts
|
|
970
|
+
* // use it on the player via player.setSponsorBlock();
|
|
971
|
+
* const sponsorBlockSegments = await player.node.setSponsorBlock(player, ["sponsor", "selfpromo"]);
|
|
972
|
+
* ```
|
|
973
|
+
*/
|
|
734
974
|
async setSponsorBlock(player, segments = ["sponsor", "selfpromo"]) {
|
|
735
975
|
// no plugin enabled
|
|
736
976
|
if (!this.info.plugins.find(v => v.name === "sponsorblock-plugin"))
|
|
@@ -749,6 +989,17 @@ export class LavalinkNode {
|
|
|
749
989
|
});
|
|
750
990
|
return;
|
|
751
991
|
}
|
|
992
|
+
/**
|
|
993
|
+
* Delete the sponsorblock plugins
|
|
994
|
+
* @param player passthrough the player
|
|
995
|
+
* @returns void
|
|
996
|
+
*
|
|
997
|
+
* @example
|
|
998
|
+
* ```ts
|
|
999
|
+
* // use it on the player via player.deleteSponsorBlock();
|
|
1000
|
+
* const sponsorBlockSegments = await player.node.deleteSponsorBlock(player);
|
|
1001
|
+
* ```
|
|
1002
|
+
*/
|
|
752
1003
|
async deleteSponsorBlock(player) {
|
|
753
1004
|
// no plugin enabled
|
|
754
1005
|
if (!this.info.plugins.find(v => v.name === "sponsorblock-plugin"))
|
|
@@ -759,7 +1010,7 @@ export class LavalinkNode {
|
|
|
759
1010
|
});
|
|
760
1011
|
return;
|
|
761
1012
|
}
|
|
762
|
-
|
|
1013
|
+
/** private util function for handling the queue end event */
|
|
763
1014
|
async queueEnd(player, track, payload) {
|
|
764
1015
|
// add previous track to the queue!
|
|
765
1016
|
player.queue.current = null;
|
|
@@ -776,7 +1027,12 @@ export class LavalinkNode {
|
|
|
776
1027
|
}
|
|
777
1028
|
}
|
|
778
1029
|
player.set("internal_autoplayStopPlaying", undefined);
|
|
779
|
-
|
|
1030
|
+
if (track && !track?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
|
|
1031
|
+
player.queue.previous.unshift(track);
|
|
1032
|
+
if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
|
|
1033
|
+
player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
|
|
1034
|
+
await player.queue.utils.save();
|
|
1035
|
+
}
|
|
780
1036
|
if (payload?.reason !== "stopped") {
|
|
781
1037
|
await player.queue.utils.save();
|
|
782
1038
|
}
|