lavalink-client 2.1.6 → 2.2.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 +11 -0
- package/dist/cjs/structures/CustomSearches/BandCampSearch.js +3 -2
- package/dist/cjs/structures/LavalinkManager.d.ts +5 -4
- package/dist/cjs/structures/LavalinkManager.js +1 -0
- package/dist/cjs/structures/LavalinkManagerStatics.js +5 -1
- package/dist/cjs/structures/Node.d.ts +10 -13
- package/dist/cjs/structures/Node.js +55 -56
- package/dist/cjs/structures/NodeManager.d.ts +1 -1
- package/dist/cjs/structures/Player.js +10 -10
- package/dist/cjs/structures/Queue.js +1 -1
- package/dist/cjs/structures/Track.d.ts +2 -0
- package/dist/cjs/structures/Utils.d.ts +12 -7
- package/dist/cjs/structures/Utils.js +6 -4
- package/dist/esm/structures/CustomSearches/BandCampSearch.js +2 -1
- package/dist/esm/structures/LavalinkManager.d.ts +5 -4
- package/dist/esm/structures/LavalinkManager.js +1 -0
- package/dist/esm/structures/LavalinkManagerStatics.js +5 -1
- package/dist/esm/structures/Node.d.ts +10 -13
- package/dist/esm/structures/Node.js +55 -56
- package/dist/esm/structures/NodeManager.d.ts +1 -1
- package/dist/esm/structures/Player.js +10 -10
- package/dist/esm/structures/Queue.js +1 -1
- package/dist/esm/structures/Track.d.ts +2 -0
- package/dist/esm/structures/Utils.d.ts +12 -7
- package/dist/esm/structures/Utils.js +6 -4
- package/dist/types/structures/LavalinkManager.d.ts +5 -4
- package/dist/types/structures/Node.d.ts +10 -13
- package/dist/types/structures/NodeManager.d.ts +1 -1
- package/dist/types/structures/Track.d.ts +2 -0
- package/dist/types/structures/Utils.d.ts +12 -7
- package/package.json +4 -2
|
@@ -47,10 +47,14 @@ export const DefaultSources = {
|
|
|
47
47
|
"flowery": "ftts",
|
|
48
48
|
"flowery.tts": "ftts",
|
|
49
49
|
"flowerytts": "ftts",
|
|
50
|
-
// Client sided search platforms
|
|
50
|
+
// Client sided search platforms (after lavalinkv4.0.6 it will search via bcsearch on the node itself)
|
|
51
51
|
"bandcamp": "bcsearch",
|
|
52
52
|
"bc": "bcsearch",
|
|
53
53
|
"bcsearch": "bcsearch",
|
|
54
|
+
// other searches:
|
|
55
|
+
"phsearch": "phsearch",
|
|
56
|
+
"pornhub": "phsearch",
|
|
57
|
+
"porn": "phsearch",
|
|
54
58
|
// local files
|
|
55
59
|
"local": "local",
|
|
56
60
|
// http requests
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import internal from "stream";
|
|
3
|
-
import { Dispatcher, Pool } from "undici";
|
|
4
3
|
import { NodeManager } from "./NodeManager";
|
|
5
4
|
import { DestroyReasonsType, Player } from "./Player";
|
|
6
5
|
import { Track } from "./Track";
|
|
7
6
|
import { Base64, InvalidLavalinkRestRequest, LavalinkPlayer, LavaSearchQuery, LavaSearchResponse, PlayerUpdateInfo, RoutePlanner, SearchQuery, SearchResult, Session } from "./Utils";
|
|
8
|
-
/**
|
|
9
|
-
export type ModifyRequest = (options:
|
|
7
|
+
/** Ability to manipulate fetch requests */
|
|
8
|
+
export type ModifyRequest = (options: RequestInit & {
|
|
9
|
+
path: string;
|
|
10
|
+
}) => void;
|
|
10
11
|
export declare const validSponsorBlocks: string[];
|
|
11
12
|
export type SponsorBlockSegment = "sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "filler";
|
|
12
13
|
export interface LavalinkNodeOptions {
|
|
@@ -24,14 +25,12 @@ export interface LavalinkNodeOptions {
|
|
|
24
25
|
id?: string;
|
|
25
26
|
/** Voice Regions of this Node */
|
|
26
27
|
regions?: string[];
|
|
27
|
-
/** Options for the undici http pool used for http requests */
|
|
28
|
-
poolOptions?: Pool.Options;
|
|
29
28
|
/** The retryAmount for the node. */
|
|
30
29
|
retryAmount?: number;
|
|
31
30
|
/** The retryDelay for the node. */
|
|
32
31
|
retryDelay?: number;
|
|
33
|
-
/**
|
|
34
|
-
|
|
32
|
+
/** signal for cancelling requests - default: AbortSignal.timeout(options.requestSignalTimeoutMS || 10000) - put <= 0 to disable */
|
|
33
|
+
requestSignalTimeoutMS?: number;
|
|
35
34
|
}
|
|
36
35
|
export interface MemoryStats {
|
|
37
36
|
/** The free memory of the allocated amount. */
|
|
@@ -145,8 +144,6 @@ export declare class LavalinkNode {
|
|
|
145
144
|
private reconnectAttempts;
|
|
146
145
|
/** The Socket of the Lavalink */
|
|
147
146
|
private socket;
|
|
148
|
-
/** The Rest Server for this Lavalink */
|
|
149
|
-
private rest;
|
|
150
147
|
/** Version of what the Lavalink Server should be */
|
|
151
148
|
private version;
|
|
152
149
|
/**
|
|
@@ -168,7 +165,7 @@ export declare class LavalinkNode {
|
|
|
168
165
|
* @param modify Used to modify the request before being sent
|
|
169
166
|
* @returns The returned data
|
|
170
167
|
*/
|
|
171
|
-
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<
|
|
168
|
+
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<any>;
|
|
172
169
|
/**
|
|
173
170
|
* Search something raw on the node, please note only add tracks to players of that node
|
|
174
171
|
* @param query SearchQuery Object
|
|
@@ -188,7 +185,7 @@ export declare class LavalinkNode {
|
|
|
188
185
|
* @param guildId
|
|
189
186
|
* @returns
|
|
190
187
|
*/
|
|
191
|
-
destroyPlayer(guildId: any): Promise<
|
|
188
|
+
destroyPlayer(guildId: any): Promise<any>;
|
|
192
189
|
/**
|
|
193
190
|
* Connect to the Lavalink Node
|
|
194
191
|
* @param sessionId Provide the Session Id of the previous connection, to resume the node and it's player(s)
|
|
@@ -266,12 +263,12 @@ export declare class LavalinkNode {
|
|
|
266
263
|
/**
|
|
267
264
|
* Release all blacklisted IP addresses into pool of IPs
|
|
268
265
|
*/
|
|
269
|
-
unmarkAllFailedAddresses: () => Promise<
|
|
266
|
+
unmarkAllFailedAddresses: () => Promise<any>;
|
|
270
267
|
};
|
|
271
268
|
/** Private Utils */
|
|
272
269
|
private validate;
|
|
273
270
|
private syncPlayerData;
|
|
274
|
-
private get
|
|
271
|
+
private get restAddress();
|
|
275
272
|
private reconnect;
|
|
276
273
|
private open;
|
|
277
274
|
private close;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isAbsolute } from "path";
|
|
2
|
-
import { Pool } from "undici";
|
|
3
2
|
import WebSocket from "ws";
|
|
4
3
|
import { DestroyReasons } from "./Player";
|
|
5
4
|
import { NodeSymbol, queueTrackEnd } from "./Utils";
|
|
@@ -43,8 +42,6 @@ export class LavalinkNode {
|
|
|
43
42
|
reconnectAttempts = 1;
|
|
44
43
|
/** The Socket of the Lavalink */
|
|
45
44
|
socket = null;
|
|
46
|
-
/** The Rest Server for this Lavalink */
|
|
47
|
-
rest;
|
|
48
45
|
/** Version of what the Lavalink Server should be */
|
|
49
46
|
version = "v4";
|
|
50
47
|
/**
|
|
@@ -57,14 +54,13 @@ export class LavalinkNode {
|
|
|
57
54
|
secure: false,
|
|
58
55
|
retryAmount: 5,
|
|
59
56
|
retryDelay: 30e3,
|
|
60
|
-
|
|
57
|
+
requestSignalTimeoutMS: 10000,
|
|
61
58
|
...options
|
|
62
59
|
};
|
|
63
60
|
this.NodeManager = manager;
|
|
64
61
|
this.validate();
|
|
65
62
|
if (this.options.secure && this.options.port !== 443)
|
|
66
63
|
throw new SyntaxError("If secure is true, then the port must be 443");
|
|
67
|
-
this.rest = new Pool(this.poolAddress, this.options.poolOptions);
|
|
68
64
|
this.options.regions = (this.options.regions || []).map(a => a.toLowerCase());
|
|
69
65
|
Object.defineProperty(this, NodeSymbol, { configurable: true, value: true });
|
|
70
66
|
}
|
|
@@ -79,15 +75,15 @@ export class LavalinkNode {
|
|
|
79
75
|
path: `/${this.version}/${endpoint.replace(/^\//gm, "")}`,
|
|
80
76
|
method: "GET",
|
|
81
77
|
headers: {
|
|
82
|
-
Authorization: this.options.authorization
|
|
78
|
+
"Authorization": this.options.authorization
|
|
83
79
|
},
|
|
84
|
-
|
|
80
|
+
signal: this.options.requestSignalTimeoutMS && this.options.requestSignalTimeoutMS > 0 ? AbortSignal.timeout(this.options.requestSignalTimeoutMS) : undefined,
|
|
85
81
|
};
|
|
86
82
|
modify?.(options);
|
|
87
|
-
const url = new URL(`${this.
|
|
83
|
+
const url = new URL(`${this.restAddress}${options.path}`);
|
|
88
84
|
url.searchParams.append("trace", "true");
|
|
89
|
-
options.path
|
|
90
|
-
const request = await
|
|
85
|
+
delete options.path;
|
|
86
|
+
const request = await fetch(url.href, options);
|
|
91
87
|
this.calls++;
|
|
92
88
|
return { request, options };
|
|
93
89
|
}
|
|
@@ -101,9 +97,9 @@ export class LavalinkNode {
|
|
|
101
97
|
const { request, options } = await this.rawRequest(endpoint, modify);
|
|
102
98
|
if (["DELETE", "PUT"].includes(options.method))
|
|
103
99
|
return;
|
|
104
|
-
if (request.
|
|
100
|
+
if (request.status === 404)
|
|
105
101
|
throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${JSON.stringify(request.headers)}`);
|
|
106
|
-
return parseAsText ? await request.
|
|
102
|
+
return parseAsText ? await request.text() : await request.json();
|
|
107
103
|
}
|
|
108
104
|
/**
|
|
109
105
|
* Search something raw on the node, please note only add tracks to players of that node
|
|
@@ -116,8 +112,8 @@ export class LavalinkNode {
|
|
|
116
112
|
this.NodeManager.LavalinkManager.utils.validateQueryString(this, Query.query, Query.source);
|
|
117
113
|
if (Query.source)
|
|
118
114
|
this.NodeManager.LavalinkManager.utils.validateSourceString(this, Query.source);
|
|
119
|
-
if (["bcsearch", "bandcamp"].includes(Query.source)) {
|
|
120
|
-
throw new Error("Bandcamp Search only works on the player!");
|
|
115
|
+
if (["bcsearch", "bandcamp"].includes(Query.source) && !this.info.sourceManagers.includes("bandcamp")) {
|
|
116
|
+
throw new Error("Bandcamp Search only works on the player (lavaplayer version < 2.2.0!");
|
|
121
117
|
}
|
|
122
118
|
let uri = `/loadtracks?identifier=`;
|
|
123
119
|
if (/^https?:\/\//.test(Query.query) || ["http", "https", "link", "uri"].includes(Query.source)) { // if it's a link simply encode it
|
|
@@ -139,12 +135,13 @@ export class LavalinkNode {
|
|
|
139
135
|
exception: res.loadType === "error" ? res.data : null,
|
|
140
136
|
pluginInfo: res.pluginInfo || {},
|
|
141
137
|
playlist: res.loadType === "playlist" ? {
|
|
138
|
+
name: res.data.info?.name || res.data.pluginInfo?.name || null,
|
|
142
139
|
title: res.data.info?.name || res.data.pluginInfo?.name || null,
|
|
143
140
|
author: res.data.info?.author || res.data.pluginInfo?.author || null,
|
|
144
141
|
thumbnail: (res.data.info?.artworkUrl) || (res.data.pluginInfo?.artworkUrl) || ((typeof res.data?.info?.selectedTrack !== "number" || res.data?.info?.selectedTrack === -1) ? null : resTracks[res.data?.info?.selectedTrack] ? (resTracks[res.data?.info?.selectedTrack]?.info?.artworkUrl || resTracks[res.data?.info?.selectedTrack]?.info?.pluginInfo?.artworkUrl) : null) || null,
|
|
145
142
|
uri: res.data.info?.url || res.data.info?.uri || res.data.info?.link || res.data.pluginInfo?.url || res.data.pluginInfo?.uri || res.data.pluginInfo?.link || null,
|
|
146
143
|
selectedTrack: typeof res.data?.info?.selectedTrack !== "number" || res.data?.info?.selectedTrack === -1 ? null : resTracks[res.data?.info?.selectedTrack] ? this.NodeManager.LavalinkManager.utils.buildTrack(resTracks[res.data?.info?.selectedTrack], requestUser) : null,
|
|
147
|
-
duration: resTracks.length ? resTracks.reduce((acc, cur) => acc + (cur?.info?.
|
|
144
|
+
duration: resTracks.length ? resTracks.reduce((acc, cur) => acc + (cur?.info?.length || 0), 0) : 0,
|
|
148
145
|
} : null,
|
|
149
146
|
tracks: (resTracks.length ? resTracks.map(t => this.NodeManager.LavalinkManager.utils.buildTrack(t, requestUser)) : [])
|
|
150
147
|
};
|
|
@@ -164,7 +161,7 @@ export class LavalinkNode {
|
|
|
164
161
|
const { request } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
|
|
165
162
|
if (throwOnEmpty === true)
|
|
166
163
|
throw new Error("Nothing found");
|
|
167
|
-
const res = (request.
|
|
164
|
+
const res = (request.status === 204 ? {} : await request.json());
|
|
168
165
|
return {
|
|
169
166
|
tracks: res.tracks?.map(v => this.NodeManager.LavalinkManager.utils.buildTrack(v, requestUser)) || [],
|
|
170
167
|
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)) })) || [],
|
|
@@ -189,7 +186,7 @@ export class LavalinkNode {
|
|
|
189
186
|
r.headers["Content-Type"] = "application/json";
|
|
190
187
|
r.body = JSON.stringify(data.playerOptions);
|
|
191
188
|
if (data.noReplace) {
|
|
192
|
-
const url = new URL(`${this.
|
|
189
|
+
const url = new URL(`${this.restAddress}${r.path}`);
|
|
193
190
|
url.searchParams.append("noReplace", data.noReplace === true && typeof data.noReplace === "boolean" ? "true" : "false");
|
|
194
191
|
r.path = url.pathname + url.search;
|
|
195
192
|
}
|
|
@@ -470,7 +467,7 @@ export class LavalinkNode {
|
|
|
470
467
|
}
|
|
471
468
|
return true;
|
|
472
469
|
}
|
|
473
|
-
get
|
|
470
|
+
get restAddress() {
|
|
474
471
|
return `http${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}`;
|
|
475
472
|
}
|
|
476
473
|
reconnect(instaReconnect = false) {
|
|
@@ -505,9 +502,9 @@ export class LavalinkNode {
|
|
|
505
502
|
clearTimeout(this.reconnectTimeout);
|
|
506
503
|
// reset the reconnect attempts amount
|
|
507
504
|
this.reconnectAttempts = 1;
|
|
508
|
-
this.info = await this.fetchInfo().catch(() => null);
|
|
505
|
+
this.info = await this.fetchInfo().catch((e) => (console.error(e, "ON-OPEN-FETCH"), null));
|
|
509
506
|
if (!this.info && ["v3", "v4"].includes(this.version)) {
|
|
510
|
-
const errorString = `Lavalink Node (${this.
|
|
507
|
+
const errorString = `Lavalink Node (${this.restAddress}) does not provide any /${this.version}/info`;
|
|
511
508
|
throw new Error(errorString);
|
|
512
509
|
}
|
|
513
510
|
this.NodeManager.emit("connect", this);
|
|
@@ -537,48 +534,50 @@ export class LavalinkNode {
|
|
|
537
534
|
this.stats = { ...payload };
|
|
538
535
|
break;
|
|
539
536
|
case "playerUpdate":
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
player.createdTimeStamp
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
player.
|
|
556
|
-
|
|
557
|
-
player.filterManager.filterUpdatedState
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if (
|
|
537
|
+
{
|
|
538
|
+
const player = this.NodeManager.LavalinkManager.getPlayer(payload.guildId);
|
|
539
|
+
if (!player)
|
|
540
|
+
return;
|
|
541
|
+
const oldPlayer = player?.toJSON();
|
|
542
|
+
if (player.get("internal_updateInterval"))
|
|
543
|
+
clearInterval(player.get("internal_updateInterval"));
|
|
544
|
+
// override the position
|
|
545
|
+
player.position = payload.state.position || 0;
|
|
546
|
+
player.lastPosition = payload.state.position || 0;
|
|
547
|
+
player.connected = payload.state.connected;
|
|
548
|
+
player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
|
|
549
|
+
if (!player.createdTimeStamp && payload.state.time)
|
|
550
|
+
player.createdTimeStamp = payload.state.time;
|
|
551
|
+
if (typeof this.NodeManager.LavalinkManager.options.playerOptions.clientBasedPositionUpdateInterval === "number" && this.NodeManager.LavalinkManager.options.playerOptions.clientBasedPositionUpdateInterval >= 10) {
|
|
552
|
+
player.set("internal_updateInterval", setInterval(() => {
|
|
553
|
+
player.position += this.NodeManager.LavalinkManager.options.playerOptions.clientBasedPositionUpdateInterval || 250;
|
|
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 {
|
|
562
565
|
player.filterManager.filterUpdatedState = 0;
|
|
563
|
-
player.seek(player.position);
|
|
564
566
|
}
|
|
565
567
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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;
|
|
569
577
|
}
|
|
570
|
-
}, this.NodeManager.LavalinkManager.options.playerOptions.clientBasedPositionUpdateInterval || 250));
|
|
571
|
-
}
|
|
572
|
-
else {
|
|
573
|
-
if (player.filterManager.filterUpdatedState >= 1) { // if no interval but instafix available, findable via the "filterUpdatedState" property
|
|
574
|
-
const maxMins = 8;
|
|
575
|
-
const currentDuration = player.queue.current?.info?.duration || 0;
|
|
576
|
-
if (currentDuration <= maxMins * 6e4 || isAbsolute(player.queue.current?.info?.uri))
|
|
577
|
-
player.seek(player.position);
|
|
578
|
-
player.filterManager.filterUpdatedState = 0;
|
|
579
578
|
}
|
|
579
|
+
this.NodeManager.LavalinkManager.emit("playerUpdate", oldPlayer, player);
|
|
580
580
|
}
|
|
581
|
-
this.NodeManager.LavalinkManager.emit("playerUpdate", oldPlayer, player);
|
|
582
581
|
break;
|
|
583
582
|
case "event":
|
|
584
583
|
this.handleEvent(payload);
|
|
@@ -5,7 +5,7 @@ import { LavalinkNode, LavalinkNodeOptions } from "./Node";
|
|
|
5
5
|
import { DestroyReasonsType } from "./Player";
|
|
6
6
|
import { LavalinkPlayer, MiniMap } from "./Utils";
|
|
7
7
|
type LavalinkNodeIdentifier = string;
|
|
8
|
-
interface NodeManagerEvents {
|
|
8
|
+
export interface NodeManagerEvents {
|
|
9
9
|
/**
|
|
10
10
|
* Emitted when a Node is created.
|
|
11
11
|
* @event Manager.nodeManager#create
|
|
@@ -129,17 +129,17 @@ export class Player {
|
|
|
129
129
|
if (options?.clientTrack && (this.LavalinkManager.utils.isTrack(options?.clientTrack) || this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))) {
|
|
130
130
|
if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))
|
|
131
131
|
await options.clientTrack.resolve(this);
|
|
132
|
-
if (typeof options.track.userData === "object")
|
|
133
|
-
options.clientTrack.userData = { ...(options?.clientTrack.userData || {}), ...(options.track
|
|
132
|
+
if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack)
|
|
133
|
+
options.clientTrack.userData = { ...(options?.clientTrack.userData || {}), ...(options.track?.userData || {}) };
|
|
134
134
|
await this.queue.add(options?.clientTrack, 0);
|
|
135
135
|
return await this.skip();
|
|
136
136
|
}
|
|
137
137
|
else if (options?.track?.encoded) {
|
|
138
138
|
// handle play encoded options manually // TODO let it resolve by lavalink!
|
|
139
139
|
const track = await this.node.decode.singleTrack(options.track?.encoded, options.track?.requester || this.queue?.current?.requester || this.queue.previous?.[0]?.requester || this.queue.tracks?.[0]?.requester || this.LavalinkManager.options.client);
|
|
140
|
-
if (typeof options.track.userData === "object")
|
|
141
|
-
track.userData = { ...(track.userData || {}), ...(options.track.userData || {}) };
|
|
142
140
|
if (track) {
|
|
141
|
+
if (typeof options.track?.userData === "object")
|
|
142
|
+
track.userData = { ...(track.userData || {}), ...(options.track.userData || {}) };
|
|
143
143
|
replaced = true;
|
|
144
144
|
this.queue.add(track, 0);
|
|
145
145
|
await queueTrackEnd(this);
|
|
@@ -149,10 +149,10 @@ export class Player {
|
|
|
149
149
|
// handle play identifier options manually // TODO let it resolve by lavalink!
|
|
150
150
|
const res = await this.search({
|
|
151
151
|
query: options?.track?.identifier
|
|
152
|
-
}, options?.track?.
|
|
153
|
-
if (typeof options.track.userData === "object")
|
|
154
|
-
res.tracks[0].userData = { ...(res.tracks[0].userData || {}), ...(options.track.userData || {}) };
|
|
152
|
+
}, options?.track?.requester || this.queue?.current?.requester || this.queue.previous?.[0]?.requester || this.queue.tracks?.[0]?.requester || this.LavalinkManager.options.client);
|
|
155
153
|
if (res.tracks[0]) {
|
|
154
|
+
if (typeof options.track?.userData === "object")
|
|
155
|
+
res.tracks[0].userData = { ...(res.tracks[0].userData || {}), ...(options.track.userData || {}) };
|
|
156
156
|
replaced = true;
|
|
157
157
|
this.queue.add(res.tracks[0], 0);
|
|
158
158
|
await queueTrackEnd(this);
|
|
@@ -164,8 +164,8 @@ export class Player {
|
|
|
164
164
|
try {
|
|
165
165
|
// resolve the unresolved track
|
|
166
166
|
await this.queue.current.resolve(this);
|
|
167
|
-
if (typeof options.track
|
|
168
|
-
this.queue.current.userData = { ...(this.queue.current
|
|
167
|
+
if (typeof options.track?.userData === "object" && this.queue.current)
|
|
168
|
+
this.queue.current.userData = { ...(this.queue.current?.userData || {}), ...(options.track?.userData || {}) };
|
|
169
169
|
}
|
|
170
170
|
catch (error) {
|
|
171
171
|
this.LavalinkManager.emit("trackError", this, this.queue.current, error);
|
|
@@ -261,7 +261,7 @@ export class Player {
|
|
|
261
261
|
*/
|
|
262
262
|
async search(query, requestUser) {
|
|
263
263
|
const Query = this.LavalinkManager.utils.transformQuery(query);
|
|
264
|
-
if (["bcsearch", "bandcamp"].includes(Query.source))
|
|
264
|
+
if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp"))
|
|
265
265
|
return await bandCampSearch(this, Query.query, requestUser);
|
|
266
266
|
return this.node.search(Query, requestUser);
|
|
267
267
|
}
|
|
@@ -76,7 +76,7 @@ export class Queue {
|
|
|
76
76
|
sync: async (override = true, dontSyncCurrent = true) => {
|
|
77
77
|
const data = await this.QueueSaver.get(this.guildId);
|
|
78
78
|
if (!data)
|
|
79
|
-
|
|
79
|
+
throw new Error(`No data found to sync for guildId: ${this.guildId}`);
|
|
80
80
|
if (!dontSyncCurrent && !this.current && (this.managerUtils.isTrack(data.current)))
|
|
81
81
|
this.current = data.current;
|
|
82
82
|
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
|
|
@@ -55,6 +55,8 @@ export interface PluginInfo {
|
|
|
55
55
|
type?: "album" | "playlist" | "artist" | "recommendations" | string;
|
|
56
56
|
/** The Identifier provided by a plugin */
|
|
57
57
|
albumName?: string;
|
|
58
|
+
/** The url of the album */
|
|
59
|
+
albumUrl?: string;
|
|
58
60
|
/** The url of the album art */
|
|
59
61
|
albumArtUrl?: string;
|
|
60
62
|
/** The url of the artist */
|
|
@@ -14,23 +14,23 @@ export type IntegerNumber = Opaque<number, 'Int'>;
|
|
|
14
14
|
export type FloatNumber = Opaque<number, 'Float'>;
|
|
15
15
|
export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "ymsearch";
|
|
16
16
|
export type LavaSrcSearchPlatform = LavaSrcSearchPlatformBase | "ftts";
|
|
17
|
-
export type DuncteSearchPlatform = "speak" | "tts";
|
|
17
|
+
export type DuncteSearchPlatform = "speak" | "phsearch" | "pornhub" | "porn" | "tts";
|
|
18
18
|
export type LavalinkClientSearchPlatform = "bcsearch";
|
|
19
19
|
export type LavalinkClientSearchPlatformResolve = "bandcamp" | "bc";
|
|
20
|
-
export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | LavalinkClientSearchPlatform;
|
|
20
|
+
export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | "bcsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | LavalinkClientSearchPlatform;
|
|
21
21
|
export type ClientCustomSearchPlatformUtils = "local" | "http" | "https" | "link" | "uri";
|
|
22
22
|
export type ClientSearchPlatform = ClientCustomSearchPlatformUtils | // for file/link requests
|
|
23
23
|
"youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform;
|
|
24
24
|
export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
|
|
25
25
|
export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "appleMusic" | "TwitchTv" | "vimeo";
|
|
26
26
|
export interface PlaylistInfo {
|
|
27
|
-
/** The playlist
|
|
28
|
-
title: string;
|
|
29
|
-
/** The playlist name (if provided instead of title) */
|
|
27
|
+
/** The playlist name */
|
|
30
28
|
name: string;
|
|
31
|
-
/** The
|
|
29
|
+
/** The playlist title (same as name) */
|
|
30
|
+
title: string;
|
|
31
|
+
/** The playlist Author */
|
|
32
32
|
author?: string;
|
|
33
|
-
/** The
|
|
33
|
+
/** The playlist Thumbnail */
|
|
34
34
|
thumbnail?: string;
|
|
35
35
|
/** A Uri to the playlist */
|
|
36
36
|
uri?: string;
|
|
@@ -168,8 +168,13 @@ export declare class MiniMap<K, V> extends Map<K, V> {
|
|
|
168
168
|
export type PlayerEvents = TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent | SponsorBlockSegmentEvents;
|
|
169
169
|
export type Severity = "COMMON" | "SUSPICIOUS" | "FAULT";
|
|
170
170
|
export interface Exception {
|
|
171
|
+
/** Severity of the error */
|
|
171
172
|
severity: Severity;
|
|
173
|
+
/** Nodejs Error */
|
|
174
|
+
error?: Error;
|
|
175
|
+
/** Message by lavalink */
|
|
172
176
|
message: string;
|
|
177
|
+
/** Cause by lavalink */
|
|
173
178
|
cause: string;
|
|
174
179
|
}
|
|
175
180
|
export interface PlayerEvent {
|
|
@@ -46,7 +46,7 @@ export class ManagerUtils {
|
|
|
46
46
|
identifier: data.info.identifier,
|
|
47
47
|
title: data.info.title,
|
|
48
48
|
author: data.info.author,
|
|
49
|
-
duration: data.info.
|
|
49
|
+
duration: data.info.duration || data.info.length,
|
|
50
50
|
artworkUrl: data.info.artworkUrl || data.pluginInfo?.artworkUrl || data.plugin?.artworkUrl,
|
|
51
51
|
uri: data.info.uri,
|
|
52
52
|
sourceName: data.info.sourceName,
|
|
@@ -202,7 +202,7 @@ export class ManagerUtils {
|
|
|
202
202
|
throw new Error("Lavalink Node has not 'soundcloud' enabled");
|
|
203
203
|
}
|
|
204
204
|
if (SourceLinksRegexes.bandcamp.test(queryString) && !node.info?.sourceManagers?.includes("bandcamp")) {
|
|
205
|
-
throw new Error("Lavalink Node has not 'bandcamp' enabled");
|
|
205
|
+
throw new Error("Lavalink Node has not 'bandcamp' enabled (introduced with lavaplayer 2.2.0 or lavalink 4.0.6)");
|
|
206
206
|
}
|
|
207
207
|
if (SourceLinksRegexes.TwitchTv.test(queryString) && !node.info?.sourceManagers?.includes("twitch")) {
|
|
208
208
|
throw new Error("Lavalink Node has not 'twitch' enabled");
|
|
@@ -234,9 +234,10 @@ export class ManagerUtils {
|
|
|
234
234
|
return;
|
|
235
235
|
}
|
|
236
236
|
transformQuery(query) {
|
|
237
|
+
const sourceOfQuery = typeof query === "string" ? undefined : (DefaultSources[(query.source?.trim?.()?.toLowerCase?.()) ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? (query.source?.trim?.()?.toLowerCase?.()));
|
|
237
238
|
const Query = {
|
|
238
239
|
query: typeof query === "string" ? query : query.query,
|
|
239
|
-
source:
|
|
240
|
+
source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
|
|
240
241
|
};
|
|
241
242
|
const foundSource = Object.keys(DefaultSources).find(source => Query.query?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
|
|
242
243
|
// ignore links...
|
|
@@ -248,10 +249,11 @@ export class ManagerUtils {
|
|
|
248
249
|
}
|
|
249
250
|
transformLavaSearchQuery(query) {
|
|
250
251
|
// transform the query object
|
|
252
|
+
const sourceOfQuery = typeof query === "string" ? undefined : (DefaultSources[(query.source?.trim?.()?.toLowerCase?.()) ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? (query.source?.trim?.()?.toLowerCase?.()));
|
|
251
253
|
const Query = {
|
|
252
254
|
query: typeof query === "string" ? query : query.query,
|
|
253
255
|
types: query.types ? ["track", "playlist", "artist", "album", "text"].filter(v => query.types?.find(x => x.toLowerCase().startsWith(v))) : ["track", "playlist", "artist", "album", /*"text"*/],
|
|
254
|
-
source:
|
|
256
|
+
source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
|
|
255
257
|
};
|
|
256
258
|
const foundSource = Object.keys(DefaultSources).find(source => Query.query.toLowerCase().startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
|
|
257
259
|
if (foundSource && DefaultSources[foundSource]) {
|
|
@@ -66,6 +66,8 @@ export interface ManagerOptions {
|
|
|
66
66
|
advancedOptions?: {
|
|
67
67
|
/** optional */
|
|
68
68
|
debugOptions?: {
|
|
69
|
+
/** For logging custom searches */
|
|
70
|
+
logCustomSearches?: boolean;
|
|
69
71
|
/** logs for debugging the "no-Audio" playing error */
|
|
70
72
|
noAudio?: boolean;
|
|
71
73
|
/** For Logging the Destroy function */
|
|
@@ -78,7 +80,7 @@ export interface ManagerOptions {
|
|
|
78
80
|
};
|
|
79
81
|
};
|
|
80
82
|
}
|
|
81
|
-
interface LavalinkManagerEvents {
|
|
83
|
+
export interface LavalinkManagerEvents {
|
|
82
84
|
/**
|
|
83
85
|
* Emitted when a Track started playing.
|
|
84
86
|
* @event Manager#trackStart
|
|
@@ -93,12 +95,12 @@ interface LavalinkManagerEvents {
|
|
|
93
95
|
* Emitted when a Track got stuck while playing.
|
|
94
96
|
* @event Manager#trackStuck
|
|
95
97
|
*/
|
|
96
|
-
"trackStuck": (player: Player, track: Track, payload: TrackStuckEvent) => void;
|
|
98
|
+
"trackStuck": (player: Player, track: Track | null, payload: TrackStuckEvent) => void;
|
|
97
99
|
/**
|
|
98
100
|
* Emitted when a Track errored.
|
|
99
101
|
* @event Manager#trackError
|
|
100
102
|
*/
|
|
101
|
-
"trackError": (player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent) => void;
|
|
103
|
+
"trackError": (player: Player, track: Track | UnresolvedTrack | null, payload: TrackExceptionEvent) => void;
|
|
102
104
|
/**
|
|
103
105
|
* Emitted when the Playing finished and no more tracks in the queue.
|
|
104
106
|
* @event Manager#queueEnd
|
|
@@ -347,4 +349,3 @@ export declare class LavalinkManager extends EventEmitter {
|
|
|
347
349
|
*/
|
|
348
350
|
sendRawData(data: VoicePacket | VoiceServer | VoiceState | ChannelDeletePacket): Promise<void>;
|
|
349
351
|
}
|
|
350
|
-
export {};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import internal from "stream";
|
|
3
|
-
import { Dispatcher, Pool } from "undici";
|
|
4
3
|
import { NodeManager } from "./NodeManager";
|
|
5
4
|
import { DestroyReasonsType, Player } from "./Player";
|
|
6
5
|
import { Track } from "./Track";
|
|
7
6
|
import { Base64, InvalidLavalinkRestRequest, LavalinkPlayer, LavaSearchQuery, LavaSearchResponse, PlayerUpdateInfo, RoutePlanner, SearchQuery, SearchResult, Session } from "./Utils";
|
|
8
|
-
/**
|
|
9
|
-
export type ModifyRequest = (options:
|
|
7
|
+
/** Ability to manipulate fetch requests */
|
|
8
|
+
export type ModifyRequest = (options: RequestInit & {
|
|
9
|
+
path: string;
|
|
10
|
+
}) => void;
|
|
10
11
|
export declare const validSponsorBlocks: string[];
|
|
11
12
|
export type SponsorBlockSegment = "sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "filler";
|
|
12
13
|
export interface LavalinkNodeOptions {
|
|
@@ -24,14 +25,12 @@ export interface LavalinkNodeOptions {
|
|
|
24
25
|
id?: string;
|
|
25
26
|
/** Voice Regions of this Node */
|
|
26
27
|
regions?: string[];
|
|
27
|
-
/** Options for the undici http pool used for http requests */
|
|
28
|
-
poolOptions?: Pool.Options;
|
|
29
28
|
/** The retryAmount for the node. */
|
|
30
29
|
retryAmount?: number;
|
|
31
30
|
/** The retryDelay for the node. */
|
|
32
31
|
retryDelay?: number;
|
|
33
|
-
/**
|
|
34
|
-
|
|
32
|
+
/** signal for cancelling requests - default: AbortSignal.timeout(options.requestSignalTimeoutMS || 10000) - put <= 0 to disable */
|
|
33
|
+
requestSignalTimeoutMS?: number;
|
|
35
34
|
}
|
|
36
35
|
export interface MemoryStats {
|
|
37
36
|
/** The free memory of the allocated amount. */
|
|
@@ -145,8 +144,6 @@ export declare class LavalinkNode {
|
|
|
145
144
|
private reconnectAttempts;
|
|
146
145
|
/** The Socket of the Lavalink */
|
|
147
146
|
private socket;
|
|
148
|
-
/** The Rest Server for this Lavalink */
|
|
149
|
-
private rest;
|
|
150
147
|
/** Version of what the Lavalink Server should be */
|
|
151
148
|
private version;
|
|
152
149
|
/**
|
|
@@ -168,7 +165,7 @@ export declare class LavalinkNode {
|
|
|
168
165
|
* @param modify Used to modify the request before being sent
|
|
169
166
|
* @returns The returned data
|
|
170
167
|
*/
|
|
171
|
-
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<
|
|
168
|
+
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<any>;
|
|
172
169
|
/**
|
|
173
170
|
* Search something raw on the node, please note only add tracks to players of that node
|
|
174
171
|
* @param query SearchQuery Object
|
|
@@ -188,7 +185,7 @@ export declare class LavalinkNode {
|
|
|
188
185
|
* @param guildId
|
|
189
186
|
* @returns
|
|
190
187
|
*/
|
|
191
|
-
destroyPlayer(guildId: any): Promise<
|
|
188
|
+
destroyPlayer(guildId: any): Promise<any>;
|
|
192
189
|
/**
|
|
193
190
|
* Connect to the Lavalink Node
|
|
194
191
|
* @param sessionId Provide the Session Id of the previous connection, to resume the node and it's player(s)
|
|
@@ -266,12 +263,12 @@ export declare class LavalinkNode {
|
|
|
266
263
|
/**
|
|
267
264
|
* Release all blacklisted IP addresses into pool of IPs
|
|
268
265
|
*/
|
|
269
|
-
unmarkAllFailedAddresses: () => Promise<
|
|
266
|
+
unmarkAllFailedAddresses: () => Promise<any>;
|
|
270
267
|
};
|
|
271
268
|
/** Private Utils */
|
|
272
269
|
private validate;
|
|
273
270
|
private syncPlayerData;
|
|
274
|
-
private get
|
|
271
|
+
private get restAddress();
|
|
275
272
|
private reconnect;
|
|
276
273
|
private open;
|
|
277
274
|
private close;
|
|
@@ -5,7 +5,7 @@ import { LavalinkNode, LavalinkNodeOptions } from "./Node";
|
|
|
5
5
|
import { DestroyReasonsType } from "./Player";
|
|
6
6
|
import { LavalinkPlayer, MiniMap } from "./Utils";
|
|
7
7
|
type LavalinkNodeIdentifier = string;
|
|
8
|
-
interface NodeManagerEvents {
|
|
8
|
+
export interface NodeManagerEvents {
|
|
9
9
|
/**
|
|
10
10
|
* Emitted when a Node is created.
|
|
11
11
|
* @event Manager.nodeManager#create
|
|
@@ -55,6 +55,8 @@ export interface PluginInfo {
|
|
|
55
55
|
type?: "album" | "playlist" | "artist" | "recommendations" | string;
|
|
56
56
|
/** The Identifier provided by a plugin */
|
|
57
57
|
albumName?: string;
|
|
58
|
+
/** The url of the album */
|
|
59
|
+
albumUrl?: string;
|
|
58
60
|
/** The url of the album art */
|
|
59
61
|
albumArtUrl?: string;
|
|
60
62
|
/** The url of the artist */
|