lavalink-client 1.1.9 → 1.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/structures/CustomSearches/BandCampSearch.d.ts +3 -0
- package/dist/cjs/structures/CustomSearches/BandCampSearch.js +36 -0
- package/dist/cjs/structures/Filters.d.ts +12 -5
- package/dist/cjs/structures/Filters.js +43 -23
- package/dist/cjs/structures/LavalinkManagerStatics.js +4 -1
- package/dist/cjs/structures/Node.d.ts +2 -1
- package/dist/cjs/structures/Node.js +25 -6
- package/dist/cjs/structures/Player.d.ts +2 -2
- package/dist/cjs/structures/Player.js +21 -15
- package/dist/cjs/structures/Utils.d.ts +11 -2
- package/dist/cjs/structures/Utils.js +15 -15
- package/dist/esm/structures/CustomSearches/BandCampSearch.d.ts +3 -0
- package/dist/esm/structures/CustomSearches/BandCampSearch.js +32 -0
- package/dist/esm/structures/Filters.d.ts +12 -5
- package/dist/esm/structures/Filters.js +43 -23
- package/dist/esm/structures/LavalinkManagerStatics.js +4 -1
- package/dist/esm/structures/Node.d.ts +2 -1
- package/dist/esm/structures/Node.js +25 -6
- package/dist/esm/structures/Player.d.ts +2 -2
- package/dist/esm/structures/Player.js +21 -15
- package/dist/esm/structures/Utils.d.ts +11 -2
- package/dist/esm/structures/Utils.js +15 -15
- package/dist/types/structures/CustomSearches/BandCampSearch.d.ts +3 -0
- package/dist/types/structures/Filters.d.ts +12 -5
- package/dist/types/structures/Node.d.ts +2 -1
- package/dist/types/structures/Player.d.ts +2 -2
- package/dist/types/structures/Utils.d.ts +11 -2
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bandCampSearch = void 0;
|
|
4
|
+
const undici_1 = require("undici");
|
|
5
|
+
const http_1 = require("http");
|
|
6
|
+
const bandCampSearch = async (player, query, requestUser) => {
|
|
7
|
+
let error = null;
|
|
8
|
+
let tracks = [];
|
|
9
|
+
try {
|
|
10
|
+
const data = await (0, undici_1.fetch)(`https://bandcamp.com/api/nusearch/2/autocomplete?q=${encodeURIComponent(query)}`, {
|
|
11
|
+
headers: {
|
|
12
|
+
'User-Agent': 'android-async-http/1.4.1 (http://loopj.com/android-async-http)',
|
|
13
|
+
'Cookie': '$Version=1'
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const json = await data.json();
|
|
17
|
+
tracks = json?.results?.filter(x => !!x && typeof x === "object" && "type" in x && x.type === "t").map?.(item => player.LavalinkManager.utils.buildUnresolvedTrack({
|
|
18
|
+
uri: item.url || item.uri,
|
|
19
|
+
artworkUrl: item.img,
|
|
20
|
+
author: item.band_name,
|
|
21
|
+
title: item.name,
|
|
22
|
+
identifier: item.id ? `${item.id}` : item.url?.split("/").reverse()[0],
|
|
23
|
+
}, http_1.request));
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
error = e;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
loadType: "search",
|
|
30
|
+
exception: error,
|
|
31
|
+
pluginInfo: {},
|
|
32
|
+
playlist: null,
|
|
33
|
+
tracks: tracks
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
exports.bandCampSearch = bandCampSearch;
|
|
@@ -95,11 +95,11 @@ export declare class FilterManager {
|
|
|
95
95
|
toggleEcho(delay?: number, decay?: number): Promise<boolean>;
|
|
96
96
|
/**
|
|
97
97
|
* Enabels / Disables the Echo effect, IMPORTANT! Only works with the correct Lavalink Plugin installed. (Optional: provide your Own Data)
|
|
98
|
-
* @param
|
|
99
|
-
* @param
|
|
98
|
+
* @param delays
|
|
99
|
+
* @param gains
|
|
100
100
|
* @returns
|
|
101
101
|
*/
|
|
102
|
-
toggleReverb(
|
|
102
|
+
toggleReverb(delays?: number[], gains?: number[]): Promise<boolean>;
|
|
103
103
|
/**
|
|
104
104
|
* Enables / Disabels a Nightcore-like filter Effect. Disables/Overwrides both: custom and Vaporwave Filter
|
|
105
105
|
* @param speed
|
|
@@ -276,8 +276,8 @@ export interface EchoFilter {
|
|
|
276
276
|
* A Plugin Filter
|
|
277
277
|
*/
|
|
278
278
|
export interface ReverbFilter {
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
delays: number[];
|
|
280
|
+
gains: number[];
|
|
281
281
|
}
|
|
282
282
|
/**
|
|
283
283
|
* Filter Data stored in the Client and partially sent to Lavalink
|
|
@@ -292,6 +292,13 @@ export interface FilterData {
|
|
|
292
292
|
distortion?: DistortionFilter;
|
|
293
293
|
channelMix?: ChannelMixFilter;
|
|
294
294
|
lowPass?: LowPassFilter;
|
|
295
|
+
pluginFilters?: Record<PluginFiltersKey, PluginFiltersValues>;
|
|
296
|
+
}
|
|
297
|
+
export type PluginFiltersKey = "lavalink-filter-plugin" | string;
|
|
298
|
+
export interface PluginFiltersValues extends LavalinkFiltersPlugin {
|
|
299
|
+
[key: string]: any;
|
|
300
|
+
}
|
|
301
|
+
export interface LavalinkFiltersPlugin {
|
|
295
302
|
echo: EchoFilter;
|
|
296
303
|
reverb: ReverbFilter;
|
|
297
304
|
}
|
|
@@ -40,14 +40,6 @@ class FilterManager {
|
|
|
40
40
|
pitch: 1,
|
|
41
41
|
rate: 1 // 0 = x
|
|
42
42
|
},
|
|
43
|
-
echo: {
|
|
44
|
-
delay: 0,
|
|
45
|
-
decay: 0
|
|
46
|
-
},
|
|
47
|
-
reverb: {
|
|
48
|
-
delay: 0,
|
|
49
|
-
decay: 0
|
|
50
|
-
},
|
|
51
43
|
rotation: {
|
|
52
44
|
rotationHz: 0
|
|
53
45
|
},
|
|
@@ -59,6 +51,18 @@ class FilterManager {
|
|
|
59
51
|
frequency: 0,
|
|
60
52
|
depth: 0 // 0 < x = 1
|
|
61
53
|
},
|
|
54
|
+
pluginFilters: {
|
|
55
|
+
/*"lavalink-filter-plugin": {
|
|
56
|
+
echo: {
|
|
57
|
+
delay: 0,
|
|
58
|
+
decay: 0
|
|
59
|
+
},
|
|
60
|
+
reverb: {
|
|
61
|
+
delays: [0.037, 0.042, 0.048, 0.053],
|
|
62
|
+
gains: [0.84, 0.83, 0.82, 0.81]
|
|
63
|
+
}
|
|
64
|
+
}*/
|
|
65
|
+
},
|
|
62
66
|
channelMix: exports.audioOutputsData.stereo,
|
|
63
67
|
/*distortion: {
|
|
64
68
|
sinOffset: 0,
|
|
@@ -83,24 +87,27 @@ class FilterManager {
|
|
|
83
87
|
*/
|
|
84
88
|
async applyPlayerFilters() {
|
|
85
89
|
const sendData = { ...this.data };
|
|
90
|
+
this.checkFiltersState();
|
|
86
91
|
if (!this.filters.volume)
|
|
87
92
|
delete sendData.volume;
|
|
88
93
|
if (!this.filters.tremolo)
|
|
89
94
|
delete sendData.tremolo;
|
|
90
95
|
if (!this.filters.vibrato)
|
|
91
96
|
delete sendData.vibrato;
|
|
92
|
-
//if(!this.filters.karaoke) delete sendData.karaoke;
|
|
93
97
|
if (!this.filters.echo)
|
|
94
|
-
delete sendData.echo;
|
|
98
|
+
delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.echo;
|
|
95
99
|
if (!this.filters.reverb)
|
|
96
|
-
delete sendData.reverb;
|
|
100
|
+
delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.reverb;
|
|
97
101
|
if (!this.filters.lowPass)
|
|
98
102
|
delete sendData.lowPass;
|
|
99
103
|
if (!this.filters.karaoke)
|
|
100
104
|
delete sendData.karaoke;
|
|
101
|
-
|
|
105
|
+
if (!this.filters.rotation)
|
|
106
|
+
delete sendData.rotation;
|
|
102
107
|
if (this.filters.audioOutput === "stereo")
|
|
103
108
|
delete sendData.channelMix;
|
|
109
|
+
if (Object.values(this.data.timescale).every(v => v === 1))
|
|
110
|
+
delete sendData.timescale;
|
|
104
111
|
if (!this.player.node.sessionId)
|
|
105
112
|
throw new Error("The Lavalink-Node is either not ready or not up to date");
|
|
106
113
|
sendData.equalizer = [...this.equalizerBands];
|
|
@@ -130,8 +137,9 @@ class FilterManager {
|
|
|
130
137
|
this.filters.rotation = this.data.rotation.rotationHz !== 0;
|
|
131
138
|
this.filters.vibrato = this.data.vibrato.frequency !== 0 || this.data.vibrato.depth !== 0;
|
|
132
139
|
this.filters.tremolo = this.data.tremolo.frequency !== 0 || this.data.tremolo.depth !== 0;
|
|
133
|
-
|
|
134
|
-
this.filters.
|
|
140
|
+
const lavalinkFilterData = (this.data.pluginFilters?.["lavalink-filter-plugin"] || { echo: { decay: 0, delay: 0 }, reverb: { gains: [], delays: [] } });
|
|
141
|
+
this.filters.echo = lavalinkFilterData.echo.decay !== 0 || lavalinkFilterData.echo.delay !== 0;
|
|
142
|
+
this.filters.reverb = lavalinkFilterData.reverb?.delays?.length !== 0 || lavalinkFilterData.reverb?.gains?.length !== 0;
|
|
135
143
|
this.filters.lowPass = this.data.lowPass.smoothing !== 0;
|
|
136
144
|
this.filters.karaoke = Object.values(this.data.karaoke).some(v => v !== 0);
|
|
137
145
|
if ((this.filters.nightcore || this.filters.vaporwave) && oldFilterTimescale) {
|
|
@@ -180,8 +188,8 @@ class FilterManager {
|
|
|
180
188
|
decay: 0
|
|
181
189
|
},
|
|
182
190
|
reverb: {
|
|
183
|
-
|
|
184
|
-
|
|
191
|
+
delays: [],
|
|
192
|
+
gains: []
|
|
185
193
|
},
|
|
186
194
|
rotation: {
|
|
187
195
|
rotationHz: 0
|
|
@@ -358,23 +366,35 @@ class FilterManager {
|
|
|
358
366
|
async toggleEcho(delay = 1, decay = 0.5) {
|
|
359
367
|
if (this.player.node.info && !this.player.node.info?.filters?.includes("echo"))
|
|
360
368
|
throw new Error("Node#Info#filters does not include the 'echo' Filter (Node has it not enable aka not installed!)");
|
|
361
|
-
this.data
|
|
362
|
-
|
|
369
|
+
if (!this.data)
|
|
370
|
+
this.data = {};
|
|
371
|
+
if (!this.data.pluginFilters)
|
|
372
|
+
this.data.pluginFilters = {};
|
|
373
|
+
if (!this.data.pluginFilters["lavalink-filter-plugin"])
|
|
374
|
+
this.data.pluginFilters["lavalink-filter-plugin"] = { echo: { decay: 0, delay: 0 }, reverb: { delays: [], gains: [] } };
|
|
375
|
+
this.data.pluginFilters["lavalink-filter-plugin"].echo.delay = this.filters.echo ? 0 : delay;
|
|
376
|
+
this.data.pluginFilters["lavalink-filter-plugin"].echo.decay = this.filters.echo ? 0 : decay;
|
|
363
377
|
this.filters.echo = !this.filters.echo;
|
|
364
378
|
await this.applyPlayerFilters();
|
|
365
379
|
return this.filters.echo;
|
|
366
380
|
}
|
|
367
381
|
/**
|
|
368
382
|
* Enabels / Disables the Echo effect, IMPORTANT! Only works with the correct Lavalink Plugin installed. (Optional: provide your Own Data)
|
|
369
|
-
* @param
|
|
370
|
-
* @param
|
|
383
|
+
* @param delays
|
|
384
|
+
* @param gains
|
|
371
385
|
* @returns
|
|
372
386
|
*/
|
|
373
|
-
async toggleReverb(
|
|
387
|
+
async toggleReverb(delays = [0.037, 0.042, 0.048, 0.053], gains = [0.84, 0.83, 0.82, 0.81]) {
|
|
374
388
|
if (this.player.node.info && !this.player.node.info?.filters?.includes("reverb"))
|
|
375
389
|
throw new Error("Node#Info#filters does not include the 'reverb' Filter (Node has it not enable aka not installed!)");
|
|
376
|
-
this.data
|
|
377
|
-
|
|
390
|
+
if (!this.data)
|
|
391
|
+
this.data = {};
|
|
392
|
+
if (!this.data.pluginFilters)
|
|
393
|
+
this.data.pluginFilters = {};
|
|
394
|
+
if (!this.data.pluginFilters["lavalink-filter-plugin"])
|
|
395
|
+
this.data.pluginFilters["lavalink-filter-plugin"] = { echo: { decay: 0, delay: 0 }, reverb: { delays: [], gains: [] } };
|
|
396
|
+
this.data.pluginFilters["lavalink-filter-plugin"].reverb.delays = this.filters.reverb ? [] : delays;
|
|
397
|
+
this.data.pluginFilters["lavalink-filter-plugin"].reverb.gains = this.filters.reverb ? [] : gains;
|
|
378
398
|
this.filters.reverb = !this.filters.reverb;
|
|
379
399
|
await this.applyPlayerFilters();
|
|
380
400
|
return this.filters.reverb;
|
|
@@ -40,7 +40,10 @@ exports.DefaultSources = {
|
|
|
40
40
|
// speak PLUGIN
|
|
41
41
|
"speak": "speak",
|
|
42
42
|
"tts": "tts",
|
|
43
|
-
"ftts": "ftts"
|
|
43
|
+
"ftts": "ftts",
|
|
44
|
+
// Client sided search platforms
|
|
45
|
+
"bandcamp": "bcsearch",
|
|
46
|
+
"bcsearch": "bcsearch",
|
|
44
47
|
};
|
|
45
48
|
exports.LavalinkPlugins = {
|
|
46
49
|
DuncteBot_Plugin: "DuncteBot-plugin",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Dispatcher, Pool } from "undici";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
4
|
import internal from "stream";
|
|
5
|
-
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64 } from "./Utils";
|
|
5
|
+
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64, SearchResult } from "./Utils";
|
|
6
6
|
import { DestroyReasonsType } from "./Player";
|
|
7
7
|
import { Track } from "./Track";
|
|
8
8
|
/** Modifies any outgoing REST requests. */
|
|
@@ -135,6 +135,7 @@ export declare class LavalinkNode {
|
|
|
135
135
|
* @returns The returned data
|
|
136
136
|
*/
|
|
137
137
|
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<unknown>;
|
|
138
|
+
search(querySourceString: string, requestUser: unknown): Promise<SearchResult>;
|
|
138
139
|
/**
|
|
139
140
|
* Update the Player State on the Lavalink Server
|
|
140
141
|
* @param data
|
|
@@ -96,6 +96,25 @@ class LavalinkNode {
|
|
|
96
96
|
throw new Error(`Node Request resulted into an error, request-URL: ${url} | headers: ${JSON.stringify(request.headers)}`);
|
|
97
97
|
return parseAsText ? await request.body.text() : await request.body.json();
|
|
98
98
|
}
|
|
99
|
+
async search(querySourceString, requestUser) {
|
|
100
|
+
const res = await this.request(`/loadsearch?query=${encodeURIComponent(decodeURIComponent(querySourceString))}`);
|
|
101
|
+
// transform the data which can be Error, Track or Track[] to enfore [Track]
|
|
102
|
+
const resTracks = res.loadType === "playlist" ? res.data?.tracks : res.loadType === "track" ? [res.data] : res.loadType === "search" ? Array.isArray(res.data) ? res.data : [res.data] : [];
|
|
103
|
+
return {
|
|
104
|
+
loadType: res.loadType,
|
|
105
|
+
exception: res.loadType === "error" ? res.data : null,
|
|
106
|
+
pluginInfo: res.pluginInfo || {},
|
|
107
|
+
playlist: res.loadType === "playlist" ? {
|
|
108
|
+
title: res.data.info?.name || res.data.pluginInfo?.name || null,
|
|
109
|
+
author: res.data.info?.author || res.data.pluginInfo?.author || null,
|
|
110
|
+
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,
|
|
111
|
+
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,
|
|
112
|
+
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,
|
|
113
|
+
duration: resTracks.length ? resTracks.reduce((acc, cur) => acc + (cur?.info?.duration || 0), 0) : 0,
|
|
114
|
+
} : null,
|
|
115
|
+
tracks: (resTracks.length ? resTracks.map(t => this.NodeManager.LavalinkManager.utils.buildTrack(t, requestUser)) : [])
|
|
116
|
+
};
|
|
117
|
+
}
|
|
99
118
|
/**
|
|
100
119
|
* Update the Player State on the Lavalink Server
|
|
101
120
|
* @param data
|
|
@@ -339,12 +358,12 @@ class LavalinkNode {
|
|
|
339
358
|
player.voice = data.playerOptions.voice;
|
|
340
359
|
if (typeof data.playerOptions.volume !== "undefined") {
|
|
341
360
|
if (this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer) {
|
|
342
|
-
player.volume = data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
343
|
-
player.lavalinkVolume = data.playerOptions.volume;
|
|
361
|
+
player.volume = Math.round(data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer);
|
|
362
|
+
player.lavalinkVolume = Math.round(data.playerOptions.volume);
|
|
344
363
|
}
|
|
345
364
|
else {
|
|
346
|
-
player.volume = data.playerOptions.volume;
|
|
347
|
-
player.lavalinkVolume = data.playerOptions.volume;
|
|
365
|
+
player.volume = Math.round(data.playerOptions.volume);
|
|
366
|
+
player.lavalinkVolume = Math.round(data.playerOptions.volume);
|
|
348
367
|
}
|
|
349
368
|
}
|
|
350
369
|
if (typeof data.playerOptions.filters !== "undefined") {
|
|
@@ -354,8 +373,8 @@ class LavalinkNode {
|
|
|
354
373
|
player.filterManager.data.timescale = data.playerOptions.filters.timescale;
|
|
355
374
|
if (data.playerOptions.filters.distortion)
|
|
356
375
|
player.filterManager.data.distortion = data.playerOptions.filters.distortion;
|
|
357
|
-
if (data.playerOptions.filters.
|
|
358
|
-
player.filterManager.data.
|
|
376
|
+
if (data.playerOptions.filters.pluginFilters)
|
|
377
|
+
player.filterManager.data.pluginFilters = data.playerOptions.filters.pluginFilters;
|
|
359
378
|
if (data.playerOptions.filters.vibrato)
|
|
360
379
|
player.filterManager.data.vibrato = data.playerOptions.filters.vibrato;
|
|
361
380
|
if (data.playerOptions.filters.volume)
|
|
@@ -142,7 +142,7 @@ export declare class Player {
|
|
|
142
142
|
query: string;
|
|
143
143
|
source: LavaSrcSearchPlatformBase;
|
|
144
144
|
types?: LavaSearchType[];
|
|
145
|
-
}, requestUser: unknown): Promise<SearchResult | LavaSearchResponse>;
|
|
145
|
+
}, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | SearchResult | LavaSearchResponse>;
|
|
146
146
|
/**
|
|
147
147
|
*
|
|
148
148
|
* @param query Query for your data
|
|
@@ -151,7 +151,7 @@ export declare class Player {
|
|
|
151
151
|
search(query: {
|
|
152
152
|
query: string;
|
|
153
153
|
source?: SearchPlatform;
|
|
154
|
-
} | string, requestUser: unknown): Promise<SearchResult>;
|
|
154
|
+
} | string, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | SearchResult>;
|
|
155
155
|
/**
|
|
156
156
|
* Pause the player
|
|
157
157
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Player = exports.DestroyReasons = void 0;
|
|
4
|
+
const BandCampSearch_1 = require("./CustomSearches/BandCampSearch");
|
|
4
5
|
const Filters_1 = require("./Filters");
|
|
5
6
|
const LavalinkManagerStatics_1 = require("./LavalinkManagerStatics");
|
|
6
7
|
const Queue_1 = require("./Queue");
|
|
@@ -73,11 +74,13 @@ class Player {
|
|
|
73
74
|
}
|
|
74
75
|
if (!this.node)
|
|
75
76
|
throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
|
|
76
|
-
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
77
|
-
this.volume *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
78
|
-
this.LavalinkManager.emit("playerCreate", this);
|
|
79
77
|
if (typeof options.volume === "number" && !isNaN(options.volume))
|
|
80
|
-
this.
|
|
78
|
+
this.volume = Number(options.volume);
|
|
79
|
+
this.volume = Math.round(Math.max(Math.min(this.volume, 1000), 0));
|
|
80
|
+
this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
81
|
+
? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
82
|
+
: this.volume), 1000), 0));
|
|
83
|
+
this.LavalinkManager.emit("playerCreate", this);
|
|
81
84
|
this.queue = new Queue_1.Queue(this.guildId, {}, new Queue_1.QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
|
|
82
85
|
}
|
|
83
86
|
/**
|
|
@@ -155,8 +158,8 @@ class Player {
|
|
|
155
158
|
let vol = Number(this.volume);
|
|
156
159
|
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
157
160
|
vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
158
|
-
this.lavalinkVolume = Math.
|
|
159
|
-
options.volume =
|
|
161
|
+
this.lavalinkVolume = Math.round(vol);
|
|
162
|
+
options.volume = this.lavalinkVolume;
|
|
160
163
|
}
|
|
161
164
|
const finalOptions = {
|
|
162
165
|
encodedTrack: track.encoded,
|
|
@@ -193,17 +196,16 @@ class Player {
|
|
|
193
196
|
volume = Number(volume);
|
|
194
197
|
if (isNaN(volume))
|
|
195
198
|
throw new TypeError("Volume must be a number.");
|
|
196
|
-
this.volume = Math.max(Math.min(volume,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
volume
|
|
200
|
-
this.lavalinkVolume = Math.floor(volume * 100) / 100;
|
|
199
|
+
this.volume = Math.round(Math.max(Math.min(volume, 1000), 0));
|
|
200
|
+
this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer
|
|
201
|
+
? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
202
|
+
: this.volume), 1000), 0));
|
|
201
203
|
const now = performance.now();
|
|
202
204
|
if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
|
|
203
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume:
|
|
205
|
+
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
|
|
204
206
|
}
|
|
205
207
|
else {
|
|
206
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume } });
|
|
208
|
+
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
|
|
207
209
|
}
|
|
208
210
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
209
211
|
return;
|
|
@@ -260,6 +262,9 @@ class Player {
|
|
|
260
262
|
this.LavalinkManager.utils.validateQueryString(this.node, Query.source);
|
|
261
263
|
else if (Query.source)
|
|
262
264
|
this.LavalinkManager.utils.validateSourceString(this.node, Query.source);
|
|
265
|
+
if (["bcsearch", "bandcamp"].includes(Query.source)) {
|
|
266
|
+
return await (0, BandCampSearch_1.bandCampSearch)(this, Query.query, requestUser);
|
|
267
|
+
}
|
|
263
268
|
// ftts query parameters: ?voice=Olivia&audio_format=ogg_opus&translate=False&silence=1000&speed=1.0 | example raw get query: https://api.flowery.pw/v1/tts?voice=Olivia&audio_format=ogg_opus&translate=False&silence=0&speed=1.0&text=Hello%20World
|
|
264
269
|
// request the data
|
|
265
270
|
const res = await this.node.request(`/loadtracks?identifier=${!/^https?:\/\//.test(Query.query) ? `${Query.source}:${Query.source === "ftts" ? "//" : ""}` : ""}${encodeURIComponent(Query.query)}`);
|
|
@@ -413,16 +418,17 @@ class Player {
|
|
|
413
418
|
const data = this.toJSON();
|
|
414
419
|
await this.node.destroyPlayer(this.guildId);
|
|
415
420
|
this.node = updateNode;
|
|
416
|
-
await this.connect();
|
|
417
421
|
const now = performance.now();
|
|
418
422
|
await this.node.updatePlayer({
|
|
419
423
|
guildId: this.guildId,
|
|
420
424
|
noReplace: false,
|
|
421
425
|
playerOptions: {
|
|
422
426
|
position: data.position,
|
|
423
|
-
volume: data.volume,
|
|
427
|
+
volume: Math.round(Math.max(Math.min(data.volume, 1000), 0)),
|
|
424
428
|
paused: data.paused,
|
|
425
429
|
filters: { ...data.filters, equalizer: data.equalizer },
|
|
430
|
+
voice: this.voice,
|
|
431
|
+
// track: this.queue.current,
|
|
426
432
|
},
|
|
427
433
|
});
|
|
428
434
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
@@ -15,8 +15,10 @@ 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
17
|
export type DuncteSearchPlatform = "speak" | "tts";
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
18
|
+
export type LavalinkClientSearchPlatform = "bcsearch";
|
|
19
|
+
export type LavalinkClientSearchPlatformResolve = "bandcamp";
|
|
20
|
+
export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | LavalinkClientSearchPlatform;
|
|
21
|
+
export type ClientSearchPlatform = "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "sp" | "spsuggestion" | "spotify" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform;
|
|
20
22
|
export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
|
|
21
23
|
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";
|
|
22
24
|
export interface PlaylistInfo {
|
|
@@ -42,6 +44,13 @@ export interface SearchResult {
|
|
|
42
44
|
playlist: PlaylistInfo | null;
|
|
43
45
|
tracks: Track[];
|
|
44
46
|
}
|
|
47
|
+
export interface UnresolvedSearchResult {
|
|
48
|
+
loadType: LoadTypes;
|
|
49
|
+
exception: Exception | null;
|
|
50
|
+
pluginInfo: PluginInfo;
|
|
51
|
+
playlist: PlaylistInfo | null;
|
|
52
|
+
tracks: UnresolvedTrack[];
|
|
53
|
+
}
|
|
45
54
|
export declare class ManagerUtils {
|
|
46
55
|
LavalinkManager: LavalinkManager | null;
|
|
47
56
|
constructor(LavalinkManager?: LavalinkManager);
|
|
@@ -56,7 +56,7 @@ class ManagerUtils {
|
|
|
56
56
|
info: query.info ? query.info : query.title ? query : undefined,
|
|
57
57
|
requester: typeof this.LavalinkManager?.options?.playerOptions?.requesterTransformer === "function" ? this.LavalinkManager?.options?.playerOptions?.requesterTransformer((query?.requester || requester)) : requester,
|
|
58
58
|
async resolve(player) {
|
|
59
|
-
const closest = await getClosestTrack(this, player
|
|
59
|
+
const closest = await getClosestTrack(this, player);
|
|
60
60
|
if (!closest)
|
|
61
61
|
throw new SyntaxError("No closest Track found");
|
|
62
62
|
Object.getOwnPropertyNames(this).forEach(prop => delete this[prop]);
|
|
@@ -148,7 +148,7 @@ class ManagerUtils {
|
|
|
148
148
|
return typeof data === "object" && !("info" in data) && typeof data.title === "string";
|
|
149
149
|
}
|
|
150
150
|
async getClosestTrack(data, player) {
|
|
151
|
-
return getClosestTrack(data, player
|
|
151
|
+
return getClosestTrack(data, player);
|
|
152
152
|
}
|
|
153
153
|
validateQueryString(node, queryString) {
|
|
154
154
|
if (!node.info)
|
|
@@ -315,12 +315,12 @@ async function applyUnresolvedData(resTrack, data, utils) {
|
|
|
315
315
|
resTrack.info[key] = data.info[key]; // add non-existing values
|
|
316
316
|
return resTrack;
|
|
317
317
|
}
|
|
318
|
-
async function getClosestTrack(data, player
|
|
318
|
+
async function getClosestTrack(data, player) {
|
|
319
319
|
if (!player || !player.node)
|
|
320
320
|
throw new RangeError("No player with a lavalink node was provided");
|
|
321
|
-
if (utils.isTrack(data))
|
|
322
|
-
return utils.buildTrack(data, data.requester);
|
|
323
|
-
if (!utils.isUnresolvedTrack(data))
|
|
321
|
+
if (player.LavalinkManager.utils.isTrack(data))
|
|
322
|
+
return player.LavalinkManager.utils.buildTrack(data, data.requester);
|
|
323
|
+
if (!player.LavalinkManager.utils.isUnresolvedTrack(data))
|
|
324
324
|
throw new RangeError("Track is not an unresolved Track");
|
|
325
325
|
if (!data?.info?.title && typeof data.encoded !== "string" && !data.info.uri)
|
|
326
326
|
throw new SyntaxError("the track uri / title / encoded Base64 string is required for unresolved tracks");
|
|
@@ -330,31 +330,31 @@ async function getClosestTrack(data, player, utils) {
|
|
|
330
330
|
if (typeof data.encoded === "string") {
|
|
331
331
|
const r = await player.node.decode.singleTrack(data.encoded, data.requester);
|
|
332
332
|
if (r)
|
|
333
|
-
return applyUnresolvedData(r, data, utils);
|
|
333
|
+
return applyUnresolvedData(r, data, player.LavalinkManager.utils);
|
|
334
334
|
}
|
|
335
335
|
// try to fetch the track via a uri if possible
|
|
336
336
|
if (typeof data.info.uri === "string") {
|
|
337
|
-
const r = await player.search({ query: data?.info?.uri }, data.requester).then(v => v.tracks[0]);
|
|
337
|
+
const r = await player.search({ query: data?.info?.uri }, data.requester).then(v => v.tracks?.[0]);
|
|
338
338
|
if (r)
|
|
339
|
-
return applyUnresolvedData(r, data, utils);
|
|
339
|
+
return applyUnresolvedData(r, data, player.LavalinkManager.utils);
|
|
340
340
|
}
|
|
341
341
|
// search the track as closely as possible
|
|
342
342
|
const query = [data.info?.title, data.info?.author].filter(str => !!str).join(" by ");
|
|
343
343
|
const sourceName = data.info?.sourceName;
|
|
344
344
|
return await player.search({
|
|
345
|
-
query, source: sourceName !== "
|
|
346
|
-
}, data.requester).then(res => {
|
|
345
|
+
query, source: sourceName !== "twitch" && sourceName !== "flowery-tts" ? sourceName : player.LavalinkManager.options?.playerOptions?.defaultSearchPlatform,
|
|
346
|
+
}, data.requester).then((res) => {
|
|
347
347
|
let trackToUse = null;
|
|
348
348
|
// try to find via author name
|
|
349
349
|
if (data.info.author && !trackToUse)
|
|
350
|
-
trackToUse = res.tracks.find(track => [data.info
|
|
350
|
+
trackToUse = res.tracks.find(track => [data.info?.author || "", `${data.info?.author} - Topic`].some(name => new RegExp(`^${escapeRegExp(name)}$`, "i").test(track.info?.author)) || new RegExp(`^${escapeRegExp(data.info?.title)}$`, "i").test(track.info?.title));
|
|
351
351
|
// try to find via duration
|
|
352
352
|
if (data.info.duration && !trackToUse)
|
|
353
|
-
trackToUse = res.tracks.find(track => (track.info
|
|
353
|
+
trackToUse = res.tracks.find(track => (track.info?.duration >= (data.info?.duration - 1500)) && (track?.info.duration <= (data.info?.duration + 1500)));
|
|
354
354
|
// try to find via isrc
|
|
355
355
|
if (data.info.isrc && !trackToUse)
|
|
356
|
-
trackToUse = res.tracks.find(track => track.info
|
|
356
|
+
trackToUse = res.tracks.find(track => track.info?.isrc === data.info?.isrc);
|
|
357
357
|
// apply unresolved data and return the track
|
|
358
|
-
return applyUnresolvedData(trackToUse || res.tracks[0], data, utils);
|
|
358
|
+
return applyUnresolvedData(trackToUse || res.tracks[0], data, player.LavalinkManager.utils);
|
|
359
359
|
});
|
|
360
360
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { fetch } from "undici";
|
|
2
|
+
import { request } from "http";
|
|
3
|
+
export const bandCampSearch = async (player, query, requestUser) => {
|
|
4
|
+
let error = null;
|
|
5
|
+
let tracks = [];
|
|
6
|
+
try {
|
|
7
|
+
const data = await fetch(`https://bandcamp.com/api/nusearch/2/autocomplete?q=${encodeURIComponent(query)}`, {
|
|
8
|
+
headers: {
|
|
9
|
+
'User-Agent': 'android-async-http/1.4.1 (http://loopj.com/android-async-http)',
|
|
10
|
+
'Cookie': '$Version=1'
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const json = await data.json();
|
|
14
|
+
tracks = json?.results?.filter(x => !!x && typeof x === "object" && "type" in x && x.type === "t").map?.(item => player.LavalinkManager.utils.buildUnresolvedTrack({
|
|
15
|
+
uri: item.url || item.uri,
|
|
16
|
+
artworkUrl: item.img,
|
|
17
|
+
author: item.band_name,
|
|
18
|
+
title: item.name,
|
|
19
|
+
identifier: item.id ? `${item.id}` : item.url?.split("/").reverse()[0],
|
|
20
|
+
}, request));
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
error = e;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
loadType: "search",
|
|
27
|
+
exception: error,
|
|
28
|
+
pluginInfo: {},
|
|
29
|
+
playlist: null,
|
|
30
|
+
tracks: tracks
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -95,11 +95,11 @@ export declare class FilterManager {
|
|
|
95
95
|
toggleEcho(delay?: number, decay?: number): Promise<boolean>;
|
|
96
96
|
/**
|
|
97
97
|
* Enabels / Disables the Echo effect, IMPORTANT! Only works with the correct Lavalink Plugin installed. (Optional: provide your Own Data)
|
|
98
|
-
* @param
|
|
99
|
-
* @param
|
|
98
|
+
* @param delays
|
|
99
|
+
* @param gains
|
|
100
100
|
* @returns
|
|
101
101
|
*/
|
|
102
|
-
toggleReverb(
|
|
102
|
+
toggleReverb(delays?: number[], gains?: number[]): Promise<boolean>;
|
|
103
103
|
/**
|
|
104
104
|
* Enables / Disabels a Nightcore-like filter Effect. Disables/Overwrides both: custom and Vaporwave Filter
|
|
105
105
|
* @param speed
|
|
@@ -276,8 +276,8 @@ export interface EchoFilter {
|
|
|
276
276
|
* A Plugin Filter
|
|
277
277
|
*/
|
|
278
278
|
export interface ReverbFilter {
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
delays: number[];
|
|
280
|
+
gains: number[];
|
|
281
281
|
}
|
|
282
282
|
/**
|
|
283
283
|
* Filter Data stored in the Client and partially sent to Lavalink
|
|
@@ -292,6 +292,13 @@ export interface FilterData {
|
|
|
292
292
|
distortion?: DistortionFilter;
|
|
293
293
|
channelMix?: ChannelMixFilter;
|
|
294
294
|
lowPass?: LowPassFilter;
|
|
295
|
+
pluginFilters?: Record<PluginFiltersKey, PluginFiltersValues>;
|
|
296
|
+
}
|
|
297
|
+
export type PluginFiltersKey = "lavalink-filter-plugin" | string;
|
|
298
|
+
export interface PluginFiltersValues extends LavalinkFiltersPlugin {
|
|
299
|
+
[key: string]: any;
|
|
300
|
+
}
|
|
301
|
+
export interface LavalinkFiltersPlugin {
|
|
295
302
|
echo: EchoFilter;
|
|
296
303
|
reverb: ReverbFilter;
|
|
297
304
|
}
|
|
@@ -37,14 +37,6 @@ export class FilterManager {
|
|
|
37
37
|
pitch: 1,
|
|
38
38
|
rate: 1 // 0 = x
|
|
39
39
|
},
|
|
40
|
-
echo: {
|
|
41
|
-
delay: 0,
|
|
42
|
-
decay: 0
|
|
43
|
-
},
|
|
44
|
-
reverb: {
|
|
45
|
-
delay: 0,
|
|
46
|
-
decay: 0
|
|
47
|
-
},
|
|
48
40
|
rotation: {
|
|
49
41
|
rotationHz: 0
|
|
50
42
|
},
|
|
@@ -56,6 +48,18 @@ export class FilterManager {
|
|
|
56
48
|
frequency: 0,
|
|
57
49
|
depth: 0 // 0 < x = 1
|
|
58
50
|
},
|
|
51
|
+
pluginFilters: {
|
|
52
|
+
/*"lavalink-filter-plugin": {
|
|
53
|
+
echo: {
|
|
54
|
+
delay: 0,
|
|
55
|
+
decay: 0
|
|
56
|
+
},
|
|
57
|
+
reverb: {
|
|
58
|
+
delays: [0.037, 0.042, 0.048, 0.053],
|
|
59
|
+
gains: [0.84, 0.83, 0.82, 0.81]
|
|
60
|
+
}
|
|
61
|
+
}*/
|
|
62
|
+
},
|
|
59
63
|
channelMix: audioOutputsData.stereo,
|
|
60
64
|
/*distortion: {
|
|
61
65
|
sinOffset: 0,
|
|
@@ -80,24 +84,27 @@ export class FilterManager {
|
|
|
80
84
|
*/
|
|
81
85
|
async applyPlayerFilters() {
|
|
82
86
|
const sendData = { ...this.data };
|
|
87
|
+
this.checkFiltersState();
|
|
83
88
|
if (!this.filters.volume)
|
|
84
89
|
delete sendData.volume;
|
|
85
90
|
if (!this.filters.tremolo)
|
|
86
91
|
delete sendData.tremolo;
|
|
87
92
|
if (!this.filters.vibrato)
|
|
88
93
|
delete sendData.vibrato;
|
|
89
|
-
//if(!this.filters.karaoke) delete sendData.karaoke;
|
|
90
94
|
if (!this.filters.echo)
|
|
91
|
-
delete sendData.echo;
|
|
95
|
+
delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.echo;
|
|
92
96
|
if (!this.filters.reverb)
|
|
93
|
-
delete sendData.reverb;
|
|
97
|
+
delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.reverb;
|
|
94
98
|
if (!this.filters.lowPass)
|
|
95
99
|
delete sendData.lowPass;
|
|
96
100
|
if (!this.filters.karaoke)
|
|
97
101
|
delete sendData.karaoke;
|
|
98
|
-
|
|
102
|
+
if (!this.filters.rotation)
|
|
103
|
+
delete sendData.rotation;
|
|
99
104
|
if (this.filters.audioOutput === "stereo")
|
|
100
105
|
delete sendData.channelMix;
|
|
106
|
+
if (Object.values(this.data.timescale).every(v => v === 1))
|
|
107
|
+
delete sendData.timescale;
|
|
101
108
|
if (!this.player.node.sessionId)
|
|
102
109
|
throw new Error("The Lavalink-Node is either not ready or not up to date");
|
|
103
110
|
sendData.equalizer = [...this.equalizerBands];
|
|
@@ -127,8 +134,9 @@ export class FilterManager {
|
|
|
127
134
|
this.filters.rotation = this.data.rotation.rotationHz !== 0;
|
|
128
135
|
this.filters.vibrato = this.data.vibrato.frequency !== 0 || this.data.vibrato.depth !== 0;
|
|
129
136
|
this.filters.tremolo = this.data.tremolo.frequency !== 0 || this.data.tremolo.depth !== 0;
|
|
130
|
-
|
|
131
|
-
this.filters.
|
|
137
|
+
const lavalinkFilterData = (this.data.pluginFilters?.["lavalink-filter-plugin"] || { echo: { decay: 0, delay: 0 }, reverb: { gains: [], delays: [] } });
|
|
138
|
+
this.filters.echo = lavalinkFilterData.echo.decay !== 0 || lavalinkFilterData.echo.delay !== 0;
|
|
139
|
+
this.filters.reverb = lavalinkFilterData.reverb?.delays?.length !== 0 || lavalinkFilterData.reverb?.gains?.length !== 0;
|
|
132
140
|
this.filters.lowPass = this.data.lowPass.smoothing !== 0;
|
|
133
141
|
this.filters.karaoke = Object.values(this.data.karaoke).some(v => v !== 0);
|
|
134
142
|
if ((this.filters.nightcore || this.filters.vaporwave) && oldFilterTimescale) {
|
|
@@ -177,8 +185,8 @@ export class FilterManager {
|
|
|
177
185
|
decay: 0
|
|
178
186
|
},
|
|
179
187
|
reverb: {
|
|
180
|
-
|
|
181
|
-
|
|
188
|
+
delays: [],
|
|
189
|
+
gains: []
|
|
182
190
|
},
|
|
183
191
|
rotation: {
|
|
184
192
|
rotationHz: 0
|
|
@@ -355,23 +363,35 @@ export class FilterManager {
|
|
|
355
363
|
async toggleEcho(delay = 1, decay = 0.5) {
|
|
356
364
|
if (this.player.node.info && !this.player.node.info?.filters?.includes("echo"))
|
|
357
365
|
throw new Error("Node#Info#filters does not include the 'echo' Filter (Node has it not enable aka not installed!)");
|
|
358
|
-
this.data
|
|
359
|
-
|
|
366
|
+
if (!this.data)
|
|
367
|
+
this.data = {};
|
|
368
|
+
if (!this.data.pluginFilters)
|
|
369
|
+
this.data.pluginFilters = {};
|
|
370
|
+
if (!this.data.pluginFilters["lavalink-filter-plugin"])
|
|
371
|
+
this.data.pluginFilters["lavalink-filter-plugin"] = { echo: { decay: 0, delay: 0 }, reverb: { delays: [], gains: [] } };
|
|
372
|
+
this.data.pluginFilters["lavalink-filter-plugin"].echo.delay = this.filters.echo ? 0 : delay;
|
|
373
|
+
this.data.pluginFilters["lavalink-filter-plugin"].echo.decay = this.filters.echo ? 0 : decay;
|
|
360
374
|
this.filters.echo = !this.filters.echo;
|
|
361
375
|
await this.applyPlayerFilters();
|
|
362
376
|
return this.filters.echo;
|
|
363
377
|
}
|
|
364
378
|
/**
|
|
365
379
|
* Enabels / Disables the Echo effect, IMPORTANT! Only works with the correct Lavalink Plugin installed. (Optional: provide your Own Data)
|
|
366
|
-
* @param
|
|
367
|
-
* @param
|
|
380
|
+
* @param delays
|
|
381
|
+
* @param gains
|
|
368
382
|
* @returns
|
|
369
383
|
*/
|
|
370
|
-
async toggleReverb(
|
|
384
|
+
async toggleReverb(delays = [0.037, 0.042, 0.048, 0.053], gains = [0.84, 0.83, 0.82, 0.81]) {
|
|
371
385
|
if (this.player.node.info && !this.player.node.info?.filters?.includes("reverb"))
|
|
372
386
|
throw new Error("Node#Info#filters does not include the 'reverb' Filter (Node has it not enable aka not installed!)");
|
|
373
|
-
this.data
|
|
374
|
-
|
|
387
|
+
if (!this.data)
|
|
388
|
+
this.data = {};
|
|
389
|
+
if (!this.data.pluginFilters)
|
|
390
|
+
this.data.pluginFilters = {};
|
|
391
|
+
if (!this.data.pluginFilters["lavalink-filter-plugin"])
|
|
392
|
+
this.data.pluginFilters["lavalink-filter-plugin"] = { echo: { decay: 0, delay: 0 }, reverb: { delays: [], gains: [] } };
|
|
393
|
+
this.data.pluginFilters["lavalink-filter-plugin"].reverb.delays = this.filters.reverb ? [] : delays;
|
|
394
|
+
this.data.pluginFilters["lavalink-filter-plugin"].reverb.gains = this.filters.reverb ? [] : gains;
|
|
375
395
|
this.filters.reverb = !this.filters.reverb;
|
|
376
396
|
await this.applyPlayerFilters();
|
|
377
397
|
return this.filters.reverb;
|
|
@@ -37,7 +37,10 @@ export const DefaultSources = {
|
|
|
37
37
|
// speak PLUGIN
|
|
38
38
|
"speak": "speak",
|
|
39
39
|
"tts": "tts",
|
|
40
|
-
"ftts": "ftts"
|
|
40
|
+
"ftts": "ftts",
|
|
41
|
+
// Client sided search platforms
|
|
42
|
+
"bandcamp": "bcsearch",
|
|
43
|
+
"bcsearch": "bcsearch",
|
|
41
44
|
};
|
|
42
45
|
export const LavalinkPlugins = {
|
|
43
46
|
DuncteBot_Plugin: "DuncteBot-plugin",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Dispatcher, Pool } from "undici";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
4
|
import internal from "stream";
|
|
5
|
-
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64 } from "./Utils";
|
|
5
|
+
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64, SearchResult } from "./Utils";
|
|
6
6
|
import { DestroyReasonsType } from "./Player";
|
|
7
7
|
import { Track } from "./Track";
|
|
8
8
|
/** Modifies any outgoing REST requests. */
|
|
@@ -135,6 +135,7 @@ export declare class LavalinkNode {
|
|
|
135
135
|
* @returns The returned data
|
|
136
136
|
*/
|
|
137
137
|
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<unknown>;
|
|
138
|
+
search(querySourceString: string, requestUser: unknown): Promise<SearchResult>;
|
|
138
139
|
/**
|
|
139
140
|
* Update the Player State on the Lavalink Server
|
|
140
141
|
* @param data
|
|
@@ -92,6 +92,25 @@ export class LavalinkNode {
|
|
|
92
92
|
throw new Error(`Node Request resulted into an error, request-URL: ${url} | headers: ${JSON.stringify(request.headers)}`);
|
|
93
93
|
return parseAsText ? await request.body.text() : await request.body.json();
|
|
94
94
|
}
|
|
95
|
+
async search(querySourceString, requestUser) {
|
|
96
|
+
const res = await this.request(`/loadsearch?query=${encodeURIComponent(decodeURIComponent(querySourceString))}`);
|
|
97
|
+
// transform the data which can be Error, Track or Track[] to enfore [Track]
|
|
98
|
+
const resTracks = res.loadType === "playlist" ? res.data?.tracks : res.loadType === "track" ? [res.data] : res.loadType === "search" ? Array.isArray(res.data) ? res.data : [res.data] : [];
|
|
99
|
+
return {
|
|
100
|
+
loadType: res.loadType,
|
|
101
|
+
exception: res.loadType === "error" ? res.data : null,
|
|
102
|
+
pluginInfo: res.pluginInfo || {},
|
|
103
|
+
playlist: res.loadType === "playlist" ? {
|
|
104
|
+
title: res.data.info?.name || res.data.pluginInfo?.name || null,
|
|
105
|
+
author: res.data.info?.author || res.data.pluginInfo?.author || null,
|
|
106
|
+
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,
|
|
107
|
+
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,
|
|
108
|
+
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,
|
|
109
|
+
duration: resTracks.length ? resTracks.reduce((acc, cur) => acc + (cur?.info?.duration || 0), 0) : 0,
|
|
110
|
+
} : null,
|
|
111
|
+
tracks: (resTracks.length ? resTracks.map(t => this.NodeManager.LavalinkManager.utils.buildTrack(t, requestUser)) : [])
|
|
112
|
+
};
|
|
113
|
+
}
|
|
95
114
|
/**
|
|
96
115
|
* Update the Player State on the Lavalink Server
|
|
97
116
|
* @param data
|
|
@@ -335,12 +354,12 @@ export class LavalinkNode {
|
|
|
335
354
|
player.voice = data.playerOptions.voice;
|
|
336
355
|
if (typeof data.playerOptions.volume !== "undefined") {
|
|
337
356
|
if (this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer) {
|
|
338
|
-
player.volume = data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
339
|
-
player.lavalinkVolume = data.playerOptions.volume;
|
|
357
|
+
player.volume = Math.round(data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer);
|
|
358
|
+
player.lavalinkVolume = Math.round(data.playerOptions.volume);
|
|
340
359
|
}
|
|
341
360
|
else {
|
|
342
|
-
player.volume = data.playerOptions.volume;
|
|
343
|
-
player.lavalinkVolume = data.playerOptions.volume;
|
|
361
|
+
player.volume = Math.round(data.playerOptions.volume);
|
|
362
|
+
player.lavalinkVolume = Math.round(data.playerOptions.volume);
|
|
344
363
|
}
|
|
345
364
|
}
|
|
346
365
|
if (typeof data.playerOptions.filters !== "undefined") {
|
|
@@ -350,8 +369,8 @@ export class LavalinkNode {
|
|
|
350
369
|
player.filterManager.data.timescale = data.playerOptions.filters.timescale;
|
|
351
370
|
if (data.playerOptions.filters.distortion)
|
|
352
371
|
player.filterManager.data.distortion = data.playerOptions.filters.distortion;
|
|
353
|
-
if (data.playerOptions.filters.
|
|
354
|
-
player.filterManager.data.
|
|
372
|
+
if (data.playerOptions.filters.pluginFilters)
|
|
373
|
+
player.filterManager.data.pluginFilters = data.playerOptions.filters.pluginFilters;
|
|
355
374
|
if (data.playerOptions.filters.vibrato)
|
|
356
375
|
player.filterManager.data.vibrato = data.playerOptions.filters.vibrato;
|
|
357
376
|
if (data.playerOptions.filters.volume)
|
|
@@ -142,7 +142,7 @@ export declare class Player {
|
|
|
142
142
|
query: string;
|
|
143
143
|
source: LavaSrcSearchPlatformBase;
|
|
144
144
|
types?: LavaSearchType[];
|
|
145
|
-
}, requestUser: unknown): Promise<SearchResult | LavaSearchResponse>;
|
|
145
|
+
}, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | SearchResult | LavaSearchResponse>;
|
|
146
146
|
/**
|
|
147
147
|
*
|
|
148
148
|
* @param query Query for your data
|
|
@@ -151,7 +151,7 @@ export declare class Player {
|
|
|
151
151
|
search(query: {
|
|
152
152
|
query: string;
|
|
153
153
|
source?: SearchPlatform;
|
|
154
|
-
} | string, requestUser: unknown): Promise<SearchResult>;
|
|
154
|
+
} | string, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | SearchResult>;
|
|
155
155
|
/**
|
|
156
156
|
* Pause the player
|
|
157
157
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bandCampSearch } from "./CustomSearches/BandCampSearch";
|
|
1
2
|
import { FilterManager } from "./Filters";
|
|
2
3
|
import { DefaultSources } from "./LavalinkManagerStatics";
|
|
3
4
|
import { Queue, QueueSaver } from "./Queue";
|
|
@@ -70,11 +71,13 @@ export class Player {
|
|
|
70
71
|
}
|
|
71
72
|
if (!this.node)
|
|
72
73
|
throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
|
|
73
|
-
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
74
|
-
this.volume *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
75
|
-
this.LavalinkManager.emit("playerCreate", this);
|
|
76
74
|
if (typeof options.volume === "number" && !isNaN(options.volume))
|
|
77
|
-
this.
|
|
75
|
+
this.volume = Number(options.volume);
|
|
76
|
+
this.volume = Math.round(Math.max(Math.min(this.volume, 1000), 0));
|
|
77
|
+
this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
78
|
+
? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
79
|
+
: this.volume), 1000), 0));
|
|
80
|
+
this.LavalinkManager.emit("playerCreate", this);
|
|
78
81
|
this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
@@ -152,8 +155,8 @@ export class Player {
|
|
|
152
155
|
let vol = Number(this.volume);
|
|
153
156
|
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
154
157
|
vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
155
|
-
this.lavalinkVolume = Math.
|
|
156
|
-
options.volume =
|
|
158
|
+
this.lavalinkVolume = Math.round(vol);
|
|
159
|
+
options.volume = this.lavalinkVolume;
|
|
157
160
|
}
|
|
158
161
|
const finalOptions = {
|
|
159
162
|
encodedTrack: track.encoded,
|
|
@@ -190,17 +193,16 @@ export class Player {
|
|
|
190
193
|
volume = Number(volume);
|
|
191
194
|
if (isNaN(volume))
|
|
192
195
|
throw new TypeError("Volume must be a number.");
|
|
193
|
-
this.volume = Math.max(Math.min(volume,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
volume
|
|
197
|
-
this.lavalinkVolume = Math.floor(volume * 100) / 100;
|
|
196
|
+
this.volume = Math.round(Math.max(Math.min(volume, 1000), 0));
|
|
197
|
+
this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer
|
|
198
|
+
? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
199
|
+
: this.volume), 1000), 0));
|
|
198
200
|
const now = performance.now();
|
|
199
201
|
if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
|
|
200
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume:
|
|
202
|
+
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
|
|
201
203
|
}
|
|
202
204
|
else {
|
|
203
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume } });
|
|
205
|
+
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
|
|
204
206
|
}
|
|
205
207
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
206
208
|
return;
|
|
@@ -257,6 +259,9 @@ export class Player {
|
|
|
257
259
|
this.LavalinkManager.utils.validateQueryString(this.node, Query.source);
|
|
258
260
|
else if (Query.source)
|
|
259
261
|
this.LavalinkManager.utils.validateSourceString(this.node, Query.source);
|
|
262
|
+
if (["bcsearch", "bandcamp"].includes(Query.source)) {
|
|
263
|
+
return await bandCampSearch(this, Query.query, requestUser);
|
|
264
|
+
}
|
|
260
265
|
// ftts query parameters: ?voice=Olivia&audio_format=ogg_opus&translate=False&silence=1000&speed=1.0 | example raw get query: https://api.flowery.pw/v1/tts?voice=Olivia&audio_format=ogg_opus&translate=False&silence=0&speed=1.0&text=Hello%20World
|
|
261
266
|
// request the data
|
|
262
267
|
const res = await this.node.request(`/loadtracks?identifier=${!/^https?:\/\//.test(Query.query) ? `${Query.source}:${Query.source === "ftts" ? "//" : ""}` : ""}${encodeURIComponent(Query.query)}`);
|
|
@@ -410,16 +415,17 @@ export class Player {
|
|
|
410
415
|
const data = this.toJSON();
|
|
411
416
|
await this.node.destroyPlayer(this.guildId);
|
|
412
417
|
this.node = updateNode;
|
|
413
|
-
await this.connect();
|
|
414
418
|
const now = performance.now();
|
|
415
419
|
await this.node.updatePlayer({
|
|
416
420
|
guildId: this.guildId,
|
|
417
421
|
noReplace: false,
|
|
418
422
|
playerOptions: {
|
|
419
423
|
position: data.position,
|
|
420
|
-
volume: data.volume,
|
|
424
|
+
volume: Math.round(Math.max(Math.min(data.volume, 1000), 0)),
|
|
421
425
|
paused: data.paused,
|
|
422
426
|
filters: { ...data.filters, equalizer: data.equalizer },
|
|
427
|
+
voice: this.voice,
|
|
428
|
+
// track: this.queue.current,
|
|
423
429
|
},
|
|
424
430
|
});
|
|
425
431
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
@@ -15,8 +15,10 @@ 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
17
|
export type DuncteSearchPlatform = "speak" | "tts";
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
18
|
+
export type LavalinkClientSearchPlatform = "bcsearch";
|
|
19
|
+
export type LavalinkClientSearchPlatformResolve = "bandcamp";
|
|
20
|
+
export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | LavalinkClientSearchPlatform;
|
|
21
|
+
export type ClientSearchPlatform = "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "sp" | "spsuggestion" | "spotify" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform;
|
|
20
22
|
export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
|
|
21
23
|
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";
|
|
22
24
|
export interface PlaylistInfo {
|
|
@@ -42,6 +44,13 @@ export interface SearchResult {
|
|
|
42
44
|
playlist: PlaylistInfo | null;
|
|
43
45
|
tracks: Track[];
|
|
44
46
|
}
|
|
47
|
+
export interface UnresolvedSearchResult {
|
|
48
|
+
loadType: LoadTypes;
|
|
49
|
+
exception: Exception | null;
|
|
50
|
+
pluginInfo: PluginInfo;
|
|
51
|
+
playlist: PlaylistInfo | null;
|
|
52
|
+
tracks: UnresolvedTrack[];
|
|
53
|
+
}
|
|
45
54
|
export declare class ManagerUtils {
|
|
46
55
|
LavalinkManager: LavalinkManager | null;
|
|
47
56
|
constructor(LavalinkManager?: LavalinkManager);
|
|
@@ -53,7 +53,7 @@ export class ManagerUtils {
|
|
|
53
53
|
info: query.info ? query.info : query.title ? query : undefined,
|
|
54
54
|
requester: typeof this.LavalinkManager?.options?.playerOptions?.requesterTransformer === "function" ? this.LavalinkManager?.options?.playerOptions?.requesterTransformer((query?.requester || requester)) : requester,
|
|
55
55
|
async resolve(player) {
|
|
56
|
-
const closest = await getClosestTrack(this, player
|
|
56
|
+
const closest = await getClosestTrack(this, player);
|
|
57
57
|
if (!closest)
|
|
58
58
|
throw new SyntaxError("No closest Track found");
|
|
59
59
|
Object.getOwnPropertyNames(this).forEach(prop => delete this[prop]);
|
|
@@ -145,7 +145,7 @@ export class ManagerUtils {
|
|
|
145
145
|
return typeof data === "object" && !("info" in data) && typeof data.title === "string";
|
|
146
146
|
}
|
|
147
147
|
async getClosestTrack(data, player) {
|
|
148
|
-
return getClosestTrack(data, player
|
|
148
|
+
return getClosestTrack(data, player);
|
|
149
149
|
}
|
|
150
150
|
validateQueryString(node, queryString) {
|
|
151
151
|
if (!node.info)
|
|
@@ -309,12 +309,12 @@ async function applyUnresolvedData(resTrack, data, utils) {
|
|
|
309
309
|
resTrack.info[key] = data.info[key]; // add non-existing values
|
|
310
310
|
return resTrack;
|
|
311
311
|
}
|
|
312
|
-
async function getClosestTrack(data, player
|
|
312
|
+
async function getClosestTrack(data, player) {
|
|
313
313
|
if (!player || !player.node)
|
|
314
314
|
throw new RangeError("No player with a lavalink node was provided");
|
|
315
|
-
if (utils.isTrack(data))
|
|
316
|
-
return utils.buildTrack(data, data.requester);
|
|
317
|
-
if (!utils.isUnresolvedTrack(data))
|
|
315
|
+
if (player.LavalinkManager.utils.isTrack(data))
|
|
316
|
+
return player.LavalinkManager.utils.buildTrack(data, data.requester);
|
|
317
|
+
if (!player.LavalinkManager.utils.isUnresolvedTrack(data))
|
|
318
318
|
throw new RangeError("Track is not an unresolved Track");
|
|
319
319
|
if (!data?.info?.title && typeof data.encoded !== "string" && !data.info.uri)
|
|
320
320
|
throw new SyntaxError("the track uri / title / encoded Base64 string is required for unresolved tracks");
|
|
@@ -324,31 +324,31 @@ async function getClosestTrack(data, player, utils) {
|
|
|
324
324
|
if (typeof data.encoded === "string") {
|
|
325
325
|
const r = await player.node.decode.singleTrack(data.encoded, data.requester);
|
|
326
326
|
if (r)
|
|
327
|
-
return applyUnresolvedData(r, data, utils);
|
|
327
|
+
return applyUnresolvedData(r, data, player.LavalinkManager.utils);
|
|
328
328
|
}
|
|
329
329
|
// try to fetch the track via a uri if possible
|
|
330
330
|
if (typeof data.info.uri === "string") {
|
|
331
|
-
const r = await player.search({ query: data?.info?.uri }, data.requester).then(v => v.tracks[0]);
|
|
331
|
+
const r = await player.search({ query: data?.info?.uri }, data.requester).then(v => v.tracks?.[0]);
|
|
332
332
|
if (r)
|
|
333
|
-
return applyUnresolvedData(r, data, utils);
|
|
333
|
+
return applyUnresolvedData(r, data, player.LavalinkManager.utils);
|
|
334
334
|
}
|
|
335
335
|
// search the track as closely as possible
|
|
336
336
|
const query = [data.info?.title, data.info?.author].filter(str => !!str).join(" by ");
|
|
337
337
|
const sourceName = data.info?.sourceName;
|
|
338
338
|
return await player.search({
|
|
339
|
-
query, source: sourceName !== "
|
|
340
|
-
}, data.requester).then(res => {
|
|
339
|
+
query, source: sourceName !== "twitch" && sourceName !== "flowery-tts" ? sourceName : player.LavalinkManager.options?.playerOptions?.defaultSearchPlatform,
|
|
340
|
+
}, data.requester).then((res) => {
|
|
341
341
|
let trackToUse = null;
|
|
342
342
|
// try to find via author name
|
|
343
343
|
if (data.info.author && !trackToUse)
|
|
344
|
-
trackToUse = res.tracks.find(track => [data.info
|
|
344
|
+
trackToUse = res.tracks.find(track => [data.info?.author || "", `${data.info?.author} - Topic`].some(name => new RegExp(`^${escapeRegExp(name)}$`, "i").test(track.info?.author)) || new RegExp(`^${escapeRegExp(data.info?.title)}$`, "i").test(track.info?.title));
|
|
345
345
|
// try to find via duration
|
|
346
346
|
if (data.info.duration && !trackToUse)
|
|
347
|
-
trackToUse = res.tracks.find(track => (track.info
|
|
347
|
+
trackToUse = res.tracks.find(track => (track.info?.duration >= (data.info?.duration - 1500)) && (track?.info.duration <= (data.info?.duration + 1500)));
|
|
348
348
|
// try to find via isrc
|
|
349
349
|
if (data.info.isrc && !trackToUse)
|
|
350
|
-
trackToUse = res.tracks.find(track => track.info
|
|
350
|
+
trackToUse = res.tracks.find(track => track.info?.isrc === data.info?.isrc);
|
|
351
351
|
// apply unresolved data and return the track
|
|
352
|
-
return applyUnresolvedData(trackToUse || res.tracks[0], data, utils);
|
|
352
|
+
return applyUnresolvedData(trackToUse || res.tracks[0], data, player.LavalinkManager.utils);
|
|
353
353
|
});
|
|
354
354
|
}
|
|
@@ -95,11 +95,11 @@ export declare class FilterManager {
|
|
|
95
95
|
toggleEcho(delay?: number, decay?: number): Promise<boolean>;
|
|
96
96
|
/**
|
|
97
97
|
* Enabels / Disables the Echo effect, IMPORTANT! Only works with the correct Lavalink Plugin installed. (Optional: provide your Own Data)
|
|
98
|
-
* @param
|
|
99
|
-
* @param
|
|
98
|
+
* @param delays
|
|
99
|
+
* @param gains
|
|
100
100
|
* @returns
|
|
101
101
|
*/
|
|
102
|
-
toggleReverb(
|
|
102
|
+
toggleReverb(delays?: number[], gains?: number[]): Promise<boolean>;
|
|
103
103
|
/**
|
|
104
104
|
* Enables / Disabels a Nightcore-like filter Effect. Disables/Overwrides both: custom and Vaporwave Filter
|
|
105
105
|
* @param speed
|
|
@@ -276,8 +276,8 @@ export interface EchoFilter {
|
|
|
276
276
|
* A Plugin Filter
|
|
277
277
|
*/
|
|
278
278
|
export interface ReverbFilter {
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
delays: number[];
|
|
280
|
+
gains: number[];
|
|
281
281
|
}
|
|
282
282
|
/**
|
|
283
283
|
* Filter Data stored in the Client and partially sent to Lavalink
|
|
@@ -292,6 +292,13 @@ export interface FilterData {
|
|
|
292
292
|
distortion?: DistortionFilter;
|
|
293
293
|
channelMix?: ChannelMixFilter;
|
|
294
294
|
lowPass?: LowPassFilter;
|
|
295
|
+
pluginFilters?: Record<PluginFiltersKey, PluginFiltersValues>;
|
|
296
|
+
}
|
|
297
|
+
export type PluginFiltersKey = "lavalink-filter-plugin" | string;
|
|
298
|
+
export interface PluginFiltersValues extends LavalinkFiltersPlugin {
|
|
299
|
+
[key: string]: any;
|
|
300
|
+
}
|
|
301
|
+
export interface LavalinkFiltersPlugin {
|
|
295
302
|
echo: EchoFilter;
|
|
296
303
|
reverb: ReverbFilter;
|
|
297
304
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Dispatcher, Pool } from "undici";
|
|
3
3
|
import { NodeManager } from "./NodeManager";
|
|
4
4
|
import internal from "stream";
|
|
5
|
-
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64 } from "./Utils";
|
|
5
|
+
import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64, SearchResult } from "./Utils";
|
|
6
6
|
import { DestroyReasonsType } from "./Player";
|
|
7
7
|
import { Track } from "./Track";
|
|
8
8
|
/** Modifies any outgoing REST requests. */
|
|
@@ -135,6 +135,7 @@ export declare class LavalinkNode {
|
|
|
135
135
|
* @returns The returned data
|
|
136
136
|
*/
|
|
137
137
|
request(endpoint: string, modify?: ModifyRequest, parseAsText?: boolean): Promise<unknown>;
|
|
138
|
+
search(querySourceString: string, requestUser: unknown): Promise<SearchResult>;
|
|
138
139
|
/**
|
|
139
140
|
* Update the Player State on the Lavalink Server
|
|
140
141
|
* @param data
|
|
@@ -142,7 +142,7 @@ export declare class Player {
|
|
|
142
142
|
query: string;
|
|
143
143
|
source: LavaSrcSearchPlatformBase;
|
|
144
144
|
types?: LavaSearchType[];
|
|
145
|
-
}, requestUser: unknown): Promise<SearchResult | LavaSearchResponse>;
|
|
145
|
+
}, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | SearchResult | LavaSearchResponse>;
|
|
146
146
|
/**
|
|
147
147
|
*
|
|
148
148
|
* @param query Query for your data
|
|
@@ -151,7 +151,7 @@ export declare class Player {
|
|
|
151
151
|
search(query: {
|
|
152
152
|
query: string;
|
|
153
153
|
source?: SearchPlatform;
|
|
154
|
-
} | string, requestUser: unknown): Promise<SearchResult>;
|
|
154
|
+
} | string, requestUser: unknown): Promise<import("./Utils").UnresolvedSearchResult | SearchResult>;
|
|
155
155
|
/**
|
|
156
156
|
* Pause the player
|
|
157
157
|
*/
|
|
@@ -15,8 +15,10 @@ 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
17
|
export type DuncteSearchPlatform = "speak" | "tts";
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
18
|
+
export type LavalinkClientSearchPlatform = "bcsearch";
|
|
19
|
+
export type LavalinkClientSearchPlatformResolve = "bandcamp";
|
|
20
|
+
export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | LavalinkClientSearchPlatform;
|
|
21
|
+
export type ClientSearchPlatform = "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "sp" | "spsuggestion" | "spotify" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform;
|
|
20
22
|
export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
|
|
21
23
|
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";
|
|
22
24
|
export interface PlaylistInfo {
|
|
@@ -42,6 +44,13 @@ export interface SearchResult {
|
|
|
42
44
|
playlist: PlaylistInfo | null;
|
|
43
45
|
tracks: Track[];
|
|
44
46
|
}
|
|
47
|
+
export interface UnresolvedSearchResult {
|
|
48
|
+
loadType: LoadTypes;
|
|
49
|
+
exception: Exception | null;
|
|
50
|
+
pluginInfo: PluginInfo;
|
|
51
|
+
playlist: PlaylistInfo | null;
|
|
52
|
+
tracks: UnresolvedTrack[];
|
|
53
|
+
}
|
|
45
54
|
export declare class ManagerUtils {
|
|
46
55
|
LavalinkManager: LavalinkManager | null;
|
|
47
56
|
constructor(LavalinkManager?: LavalinkManager);
|
package/package.json
CHANGED