lavalink-client 2.5.7 → 2.5.9
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 +10 -2
- package/dist/index.d.mts +3046 -0
- package/dist/index.d.ts +3046 -0
- package/dist/index.js +4993 -0
- package/dist/index.mjs +4932 -0
- package/package.json +21 -24
- package/dist/cjs/index.d.ts +0 -16
- package/dist/cjs/index.js +0 -19
- package/dist/cjs/package.json +0 -3
- package/dist/cjs/structures/Constants.d.ts +0 -90
- package/dist/cjs/structures/Constants.js +0 -296
- package/dist/cjs/structures/CustomSearches/BandCampSearch.d.ts +0 -3
- package/dist/cjs/structures/CustomSearches/BandCampSearch.js +0 -39
- package/dist/cjs/structures/Filters.d.ts +0 -169
- package/dist/cjs/structures/Filters.js +0 -700
- package/dist/cjs/structures/LavalinkManager.d.ts +0 -232
- package/dist/cjs/structures/LavalinkManager.js +0 -621
- package/dist/cjs/structures/LavalinkManagerStatics.d.ts +0 -15
- package/dist/cjs/structures/LavalinkManagerStatics.js +0 -149
- package/dist/cjs/structures/Node.d.ts +0 -523
- package/dist/cjs/structures/Node.js +0 -1605
- package/dist/cjs/structures/NodeManager.d.ts +0 -100
- package/dist/cjs/structures/NodeManager.js +0 -224
- package/dist/cjs/structures/Player.d.ts +0 -223
- package/dist/cjs/structures/Player.js +0 -807
- package/dist/cjs/structures/Queue.d.ts +0 -186
- package/dist/cjs/structures/Queue.js +0 -390
- package/dist/cjs/structures/Types/Filters.d.ts +0 -190
- package/dist/cjs/structures/Types/Filters.js +0 -2
- package/dist/cjs/structures/Types/Manager.d.ts +0 -271
- package/dist/cjs/structures/Types/Manager.js +0 -2
- package/dist/cjs/structures/Types/Node.d.ts +0 -238
- package/dist/cjs/structures/Types/Node.js +0 -2
- package/dist/cjs/structures/Types/Player.d.ts +0 -114
- package/dist/cjs/structures/Types/Player.js +0 -2
- package/dist/cjs/structures/Types/Queue.d.ts +0 -35
- package/dist/cjs/structures/Types/Queue.js +0 -2
- package/dist/cjs/structures/Types/Track.d.ts +0 -134
- package/dist/cjs/structures/Types/Track.js +0 -2
- package/dist/cjs/structures/Types/Utils.d.ts +0 -443
- package/dist/cjs/structures/Types/Utils.js +0 -2
- package/dist/cjs/structures/Utils.d.ts +0 -116
- package/dist/cjs/structures/Utils.js +0 -567
- package/dist/esm/index.d.ts +0 -16
- package/dist/esm/index.js +0 -16
- package/dist/esm/package.json +0 -3
- package/dist/esm/structures/Constants.d.ts +0 -90
- package/dist/esm/structures/Constants.js +0 -293
- package/dist/esm/structures/CustomSearches/BandCampSearch.d.ts +0 -3
- package/dist/esm/structures/CustomSearches/BandCampSearch.js +0 -35
- package/dist/esm/structures/Filters.d.ts +0 -169
- package/dist/esm/structures/Filters.js +0 -696
- package/dist/esm/structures/LavalinkManager.d.ts +0 -232
- package/dist/esm/structures/LavalinkManager.js +0 -617
- package/dist/esm/structures/LavalinkManagerStatics.d.ts +0 -15
- package/dist/esm/structures/LavalinkManagerStatics.js +0 -146
- package/dist/esm/structures/Node.d.ts +0 -523
- package/dist/esm/structures/Node.js +0 -1600
- package/dist/esm/structures/NodeManager.d.ts +0 -100
- package/dist/esm/structures/NodeManager.js +0 -220
- package/dist/esm/structures/Player.d.ts +0 -223
- package/dist/esm/structures/Player.js +0 -803
- package/dist/esm/structures/Queue.d.ts +0 -186
- package/dist/esm/structures/Queue.js +0 -384
- package/dist/esm/structures/Types/Filters.d.ts +0 -190
- package/dist/esm/structures/Types/Filters.js +0 -1
- package/dist/esm/structures/Types/Manager.d.ts +0 -271
- package/dist/esm/structures/Types/Manager.js +0 -1
- package/dist/esm/structures/Types/Node.d.ts +0 -238
- package/dist/esm/structures/Types/Node.js +0 -1
- package/dist/esm/structures/Types/Player.d.ts +0 -114
- package/dist/esm/structures/Types/Player.js +0 -1
- package/dist/esm/structures/Types/Queue.d.ts +0 -35
- package/dist/esm/structures/Types/Queue.js +0 -1
- package/dist/esm/structures/Types/Track.d.ts +0 -134
- package/dist/esm/structures/Types/Track.js +0 -1
- package/dist/esm/structures/Types/Utils.d.ts +0 -443
- package/dist/esm/structures/Types/Utils.js +0 -1
- package/dist/esm/structures/Utils.d.ts +0 -116
- package/dist/esm/structures/Utils.js +0 -559
- package/dist/types/index.d.ts +0 -16
- package/dist/types/structures/Constants.d.ts +0 -90
- package/dist/types/structures/CustomSearches/BandCampSearch.d.ts +0 -3
- package/dist/types/structures/Filters.d.ts +0 -169
- package/dist/types/structures/LavalinkManager.d.ts +0 -232
- package/dist/types/structures/LavalinkManagerStatics.d.ts +0 -15
- package/dist/types/structures/Node.d.ts +0 -523
- package/dist/types/structures/NodeManager.d.ts +0 -100
- package/dist/types/structures/Player.d.ts +0 -223
- package/dist/types/structures/Queue.d.ts +0 -186
- package/dist/types/structures/Types/Filters.d.ts +0 -190
- package/dist/types/structures/Types/Manager.d.ts +0 -271
- package/dist/types/structures/Types/Node.d.ts +0 -238
- package/dist/types/structures/Types/Player.d.ts +0 -114
- package/dist/types/structures/Types/Queue.d.ts +0 -35
- package/dist/types/structures/Types/Track.d.ts +0 -134
- package/dist/types/structures/Types/Utils.d.ts +0 -443
- package/dist/types/structures/Utils.d.ts +0 -116
|
@@ -1,803 +0,0 @@
|
|
|
1
|
-
import { DebugEvents } from "./Constants.js";
|
|
2
|
-
import { bandCampSearch } from "./CustomSearches/BandCampSearch.js";
|
|
3
|
-
import { FilterManager } from "./Filters.js";
|
|
4
|
-
import { Queue, QueueSaver } from "./Queue.js";
|
|
5
|
-
import { queueTrackEnd, safeStringify } from "./Utils.js";
|
|
6
|
-
export class Player {
|
|
7
|
-
/** Filter Manager per player */
|
|
8
|
-
filterManager;
|
|
9
|
-
/** circular reference to the lavalink Manager from the Player for easier use */
|
|
10
|
-
LavalinkManager;
|
|
11
|
-
/** Player options currently used, mutation doesn't affect player's state */
|
|
12
|
-
options;
|
|
13
|
-
/** The lavalink node assigned the the player, don't change it manually */
|
|
14
|
-
node;
|
|
15
|
-
/** The queue from the player */
|
|
16
|
-
queue;
|
|
17
|
-
/** The Guild Id of the Player */
|
|
18
|
-
guildId;
|
|
19
|
-
/** The Voice Channel Id of the Player */
|
|
20
|
-
voiceChannelId = null;
|
|
21
|
-
/** The Text Channel Id of the Player */
|
|
22
|
-
textChannelId = null;
|
|
23
|
-
/** States if the Bot is supposed to be outputting audio */
|
|
24
|
-
playing = false;
|
|
25
|
-
/** States if the Bot is paused or not */
|
|
26
|
-
paused = false;
|
|
27
|
-
/** Repeat Mode of the Player */
|
|
28
|
-
repeatMode = "off";
|
|
29
|
-
/** Player's ping */
|
|
30
|
-
ping = {
|
|
31
|
-
/* Response time for rest actions with Lavalink Server */
|
|
32
|
-
lavalink: 0,
|
|
33
|
-
/* Latency of the Discord's Websocket Voice Server */
|
|
34
|
-
ws: 0
|
|
35
|
-
};
|
|
36
|
-
/** The Display Volume */
|
|
37
|
-
volume = 100;
|
|
38
|
-
/** The Volume Lavalink actually is outputting */
|
|
39
|
-
lavalinkVolume = 100;
|
|
40
|
-
/** The current Positin of the player (Calculated) */
|
|
41
|
-
get position() {
|
|
42
|
-
return this.lastPosition + (this.lastPositionChange ? Date.now() - this.lastPositionChange : 0);
|
|
43
|
-
}
|
|
44
|
-
/** The timestamp when the last position change update happened */
|
|
45
|
-
lastPositionChange = null;
|
|
46
|
-
/** The current Positin of the player (from Lavalink) */
|
|
47
|
-
lastPosition = 0;
|
|
48
|
-
lastSavedPosition = 0;
|
|
49
|
-
/** When the player was created [Timestamp in Ms] (from lavalink) */
|
|
50
|
-
createdTimeStamp;
|
|
51
|
-
/** The Player Connection's State (from Lavalink) */
|
|
52
|
-
connected = false;
|
|
53
|
-
/** Voice Server Data (from Lavalink) */
|
|
54
|
-
voice = {
|
|
55
|
-
endpoint: null,
|
|
56
|
-
sessionId: null,
|
|
57
|
-
token: null
|
|
58
|
-
};
|
|
59
|
-
voiceState = {
|
|
60
|
-
selfDeaf: false,
|
|
61
|
-
selfMute: false,
|
|
62
|
-
serverDeaf: false,
|
|
63
|
-
serverMute: false,
|
|
64
|
-
suppress: false,
|
|
65
|
-
};
|
|
66
|
-
/** Custom data for the player */
|
|
67
|
-
data = {};
|
|
68
|
-
/**
|
|
69
|
-
* Create a new Player
|
|
70
|
-
* @param options
|
|
71
|
-
* @param LavalinkManager
|
|
72
|
-
*/
|
|
73
|
-
constructor(options, LavalinkManager, dontEmitPlayerCreateEvent) {
|
|
74
|
-
if (typeof options?.customData === "object")
|
|
75
|
-
for (const [key, value] of Object.entries(options.customData))
|
|
76
|
-
this.set(key, value);
|
|
77
|
-
this.options = options;
|
|
78
|
-
this.filterManager = new FilterManager(this);
|
|
79
|
-
this.LavalinkManager = LavalinkManager;
|
|
80
|
-
this.guildId = this.options.guildId;
|
|
81
|
-
this.voiceChannelId = this.options.voiceChannelId;
|
|
82
|
-
this.textChannelId = this.options.textChannelId || null;
|
|
83
|
-
this.node = typeof this.options.node === "string"
|
|
84
|
-
? this.LavalinkManager.nodeManager.nodes.get(this.options.node)
|
|
85
|
-
: this.options.node;
|
|
86
|
-
if (!this.node || typeof this.node.request !== "function") {
|
|
87
|
-
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
88
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerCreateNodeNotFound, {
|
|
89
|
-
state: "warn",
|
|
90
|
-
message: `Player was created with provided node Id: ${this.options.node}, but no node with that Id was found.`,
|
|
91
|
-
functionLayer: "Player > constructor()",
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
const least = this.LavalinkManager.nodeManager.leastUsedNodes();
|
|
95
|
-
this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
|
|
96
|
-
}
|
|
97
|
-
if (!this.node)
|
|
98
|
-
throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
|
|
99
|
-
if (typeof options.volume === "number" && !isNaN(options.volume))
|
|
100
|
-
this.volume = Number(options.volume);
|
|
101
|
-
this.volume = Math.round(Math.max(Math.min(this.volume, 1000), 0));
|
|
102
|
-
this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
103
|
-
? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
104
|
-
: this.volume), 1000), 0));
|
|
105
|
-
if (!dontEmitPlayerCreateEvent)
|
|
106
|
-
this.LavalinkManager.emit("playerCreate", this);
|
|
107
|
-
this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Set custom data.
|
|
111
|
-
* @param key
|
|
112
|
-
* @param value
|
|
113
|
-
*/
|
|
114
|
-
set(key, value) {
|
|
115
|
-
this.data[key] = value;
|
|
116
|
-
return this;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Get custom data.
|
|
120
|
-
* @param key
|
|
121
|
-
*/
|
|
122
|
-
get(key) {
|
|
123
|
-
return this.data[key];
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* CLears all the custom data.
|
|
127
|
-
*/
|
|
128
|
-
clearData() {
|
|
129
|
-
const toKeep = Object.keys(this.data).filter(v => v.startsWith("internal_"));
|
|
130
|
-
for (const key in this.data) {
|
|
131
|
-
if (toKeep.includes(key))
|
|
132
|
-
continue;
|
|
133
|
-
delete this.data[key];
|
|
134
|
-
}
|
|
135
|
-
return this;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Get all custom Data
|
|
139
|
-
*/
|
|
140
|
-
getAllData() {
|
|
141
|
-
return Object.fromEntries(Object.entries(this.data).filter(v => !v[0].startsWith("internal_")));
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Play the next track from the queue / a specific track, with playoptions for Lavalink
|
|
145
|
-
* @param options
|
|
146
|
-
*/
|
|
147
|
-
async play(options = {}) {
|
|
148
|
-
if (this.get("internal_queueempty")) {
|
|
149
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
150
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayQueueEmptyTimeoutClear, {
|
|
151
|
-
state: "log",
|
|
152
|
-
message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`,
|
|
153
|
-
functionLayer: "Player > play()",
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
this.LavalinkManager.emit("playerQueueEmptyCancel", this);
|
|
157
|
-
clearTimeout(this.get("internal_queueempty"));
|
|
158
|
-
this.set("internal_queueempty", undefined);
|
|
159
|
-
}
|
|
160
|
-
// if clientTrack provided, override options.track object
|
|
161
|
-
if (options?.clientTrack && (this.LavalinkManager.utils.isTrack(options?.clientTrack) || this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))) {
|
|
162
|
-
if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack)) {
|
|
163
|
-
try {
|
|
164
|
-
// resolve the unresolved track
|
|
165
|
-
await options.clientTrack.resolve(this);
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
169
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
|
|
170
|
-
state: "error",
|
|
171
|
-
error: error,
|
|
172
|
-
message: `Player Play was called with clientTrack, Song is unresolved, but couldn't resolve it`,
|
|
173
|
-
functionLayer: "Player > play() > resolve currentTrack",
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
this.LavalinkManager.emit("trackError", this, this.queue.current, error);
|
|
177
|
-
if (options && "clientTrack" in options)
|
|
178
|
-
delete options.clientTrack;
|
|
179
|
-
if (options && "track" in options)
|
|
180
|
-
delete options.track;
|
|
181
|
-
// try to play the next track if possible
|
|
182
|
-
if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
|
|
183
|
-
return this.play(options);
|
|
184
|
-
return this;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack)
|
|
188
|
-
options.clientTrack.userData = {
|
|
189
|
-
...(typeof options?.clientTrack?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(options?.clientTrack?.requester || {}) } : {}),
|
|
190
|
-
...options?.clientTrack.userData,
|
|
191
|
-
...options.track?.userData,
|
|
192
|
-
};
|
|
193
|
-
options.track = {
|
|
194
|
-
encoded: options.clientTrack?.encoded,
|
|
195
|
-
requester: options.clientTrack?.requester,
|
|
196
|
-
userData: options.clientTrack?.userData,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
// if either encoded or identifier is provided generate the data to play them
|
|
200
|
-
if (options?.track?.encoded || options?.track?.identifier) {
|
|
201
|
-
this.queue.current = options.clientTrack || null;
|
|
202
|
-
this.queue.utils.save();
|
|
203
|
-
if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
|
|
204
|
-
this.volume = Math.max(Math.min(options?.volume, 500), 0);
|
|
205
|
-
let vol = Number(this.volume);
|
|
206
|
-
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
207
|
-
vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
208
|
-
this.lavalinkVolume = Math.round(vol);
|
|
209
|
-
options.volume = this.lavalinkVolume;
|
|
210
|
-
}
|
|
211
|
-
const track = Object.fromEntries(Object.entries({
|
|
212
|
-
encoded: options.track.encoded,
|
|
213
|
-
identifier: options.track.identifier,
|
|
214
|
-
userData: {
|
|
215
|
-
...(typeof options?.track?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {}) } : {}),
|
|
216
|
-
...options.track.userData,
|
|
217
|
-
}
|
|
218
|
-
}).filter(v => typeof v[1] !== "undefined"));
|
|
219
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
220
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayWithTrackReplace, {
|
|
221
|
-
state: "log",
|
|
222
|
-
message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`,
|
|
223
|
-
functionLayer: "Player > play()",
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
return this.node.updatePlayer({
|
|
227
|
-
guildId: this.guildId,
|
|
228
|
-
noReplace: false,
|
|
229
|
-
playerOptions: Object.fromEntries(Object.entries({
|
|
230
|
-
track,
|
|
231
|
-
position: options.position ?? undefined,
|
|
232
|
-
paused: options.paused ?? undefined,
|
|
233
|
-
endTime: options?.endTime ?? undefined,
|
|
234
|
-
filters: options?.filters ?? undefined,
|
|
235
|
-
volume: options.volume ?? this.lavalinkVolume ?? undefined,
|
|
236
|
-
voice: options.voice ?? undefined,
|
|
237
|
-
}).filter(v => typeof v[1] !== "undefined")),
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
if (!this.queue.current && this.queue.tracks.length)
|
|
241
|
-
await queueTrackEnd(this);
|
|
242
|
-
if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
|
|
243
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
244
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrack, {
|
|
245
|
-
state: "log",
|
|
246
|
-
message: `Player Play was called, current Queue Song is unresolved, resolving the track.`,
|
|
247
|
-
functionLayer: "Player > play()",
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
try {
|
|
251
|
-
// resolve the unresolved track
|
|
252
|
-
await this.queue.current.resolve(this);
|
|
253
|
-
if (typeof options.track?.userData === "object" && this.queue.current)
|
|
254
|
-
this.queue.current.userData = {
|
|
255
|
-
...(typeof this.queue.current?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(this.queue.current?.requester || {}) } : {}),
|
|
256
|
-
...this.queue.current?.userData,
|
|
257
|
-
...options.track?.userData
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
catch (error) {
|
|
261
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
262
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
|
|
263
|
-
state: "error",
|
|
264
|
-
error: error,
|
|
265
|
-
message: `Player Play was called, current Queue Song is unresolved, but couldn't resolve it`,
|
|
266
|
-
functionLayer: "Player > play() > resolve currentTrack",
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
this.LavalinkManager.emit("trackError", this, this.queue.current, error);
|
|
270
|
-
if (options && "clientTrack" in options)
|
|
271
|
-
delete options.clientTrack;
|
|
272
|
-
if (options && "track" in options)
|
|
273
|
-
delete options.track;
|
|
274
|
-
// get rid of the current song without shifting the queue, so that the shifting can happen inside the next .play() call when "autoSkipOnResolveError" is true
|
|
275
|
-
await queueTrackEnd(this, true);
|
|
276
|
-
// try to play the next track if possible
|
|
277
|
-
if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
|
|
278
|
-
return this.play(options);
|
|
279
|
-
return this;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (!this.queue.current)
|
|
283
|
-
throw new Error(`There is no Track in the Queue, nor provided in the PlayOptions`);
|
|
284
|
-
if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
|
|
285
|
-
this.volume = Math.max(Math.min(options?.volume, 500), 0);
|
|
286
|
-
let vol = Number(this.volume);
|
|
287
|
-
if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
|
|
288
|
-
vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
|
|
289
|
-
this.lavalinkVolume = Math.round(vol);
|
|
290
|
-
options.volume = this.lavalinkVolume;
|
|
291
|
-
}
|
|
292
|
-
const finalOptions = Object.fromEntries(Object.entries({
|
|
293
|
-
track: {
|
|
294
|
-
encoded: this.queue.current?.encoded || null,
|
|
295
|
-
// identifier: options.identifier,
|
|
296
|
-
userData: {
|
|
297
|
-
...(typeof this.queue.current?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(this.queue.current?.requester || {}) } : {}),
|
|
298
|
-
...options?.track?.userData,
|
|
299
|
-
...this.queue.current?.userData,
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
volume: this.lavalinkVolume,
|
|
303
|
-
position: options?.position ?? 0,
|
|
304
|
-
endTime: options?.endTime ?? undefined,
|
|
305
|
-
filters: options?.filters ?? undefined,
|
|
306
|
-
paused: options?.paused ?? undefined,
|
|
307
|
-
voice: options?.voice ?? undefined
|
|
308
|
-
}).filter(v => typeof v[1] !== "undefined"));
|
|
309
|
-
if ((typeof finalOptions.position !== "undefined" && isNaN(finalOptions.position)) || (typeof finalOptions.position === "number" && (finalOptions.position < 0 || finalOptions.position >= this.queue.current.info.duration)))
|
|
310
|
-
throw new Error("PlayerOption#position must be a positive number, less than track's duration");
|
|
311
|
-
if ((typeof finalOptions.volume !== "undefined" && isNaN(finalOptions.volume) || (typeof finalOptions.volume === "number" && finalOptions.volume < 0)))
|
|
312
|
-
throw new Error("PlayerOption#volume must be a positive number");
|
|
313
|
-
if ((typeof finalOptions.endTime !== "undefined" && isNaN(finalOptions.endTime)) || (typeof finalOptions.endTime === "number" && (finalOptions.endTime < 0 || finalOptions.endTime >= this.queue.current.info.duration)))
|
|
314
|
-
throw new Error("PlayerOption#endTime must be a positive number, less than track's duration");
|
|
315
|
-
if (typeof finalOptions.position === "number" && typeof finalOptions.endTime === "number" && finalOptions.endTime < finalOptions.position)
|
|
316
|
-
throw new Error("PlayerOption#endTime must be bigger than PlayerOption#position");
|
|
317
|
-
const now = performance.now();
|
|
318
|
-
await this.node.updatePlayer({
|
|
319
|
-
guildId: this.guildId,
|
|
320
|
-
noReplace: (options?.noReplace ?? false),
|
|
321
|
-
playerOptions: finalOptions,
|
|
322
|
-
});
|
|
323
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
324
|
-
return this;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Set the Volume for the Player
|
|
328
|
-
* @param volume The Volume in percent
|
|
329
|
-
* @param ignoreVolumeDecrementer If it should ignore the volumedecrementer option
|
|
330
|
-
*/
|
|
331
|
-
async setVolume(volume, ignoreVolumeDecrementer = false) {
|
|
332
|
-
volume = Number(volume);
|
|
333
|
-
if (isNaN(volume))
|
|
334
|
-
throw new TypeError("Volume must be a number.");
|
|
335
|
-
this.volume = Math.round(Math.max(Math.min(volume, 1000), 0));
|
|
336
|
-
this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer
|
|
337
|
-
? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
|
|
338
|
-
: this.volume), 1000), 0));
|
|
339
|
-
const now = performance.now();
|
|
340
|
-
if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
|
|
341
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
342
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerVolumeAsFilter, {
|
|
343
|
-
state: "log",
|
|
344
|
-
message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`,
|
|
345
|
-
functionLayer: "Player > setVolume()",
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
|
|
349
|
-
}
|
|
350
|
-
else {
|
|
351
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
|
|
352
|
-
}
|
|
353
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
354
|
-
return this;
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Search for a track
|
|
358
|
-
* @param query The query to search for
|
|
359
|
-
* @param requestUser The user that requested the track
|
|
360
|
-
* @param throwOnEmpty If an error should be thrown if no track is found
|
|
361
|
-
* @returns The search result
|
|
362
|
-
*/
|
|
363
|
-
async lavaSearch(query, requestUser, throwOnEmpty = false) {
|
|
364
|
-
return this.node.lavaSearch(query, requestUser, throwOnEmpty);
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Set the SponsorBlock
|
|
368
|
-
* @param segments The segments to set
|
|
369
|
-
*/
|
|
370
|
-
async setSponsorBlock(segments = ["sponsor", "selfpromo"]) {
|
|
371
|
-
return this.node.setSponsorBlock(this, segments);
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Get the SponsorBlock
|
|
375
|
-
*/
|
|
376
|
-
async getSponsorBlock() {
|
|
377
|
-
return this.node.getSponsorBlock(this);
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Delete the SponsorBlock
|
|
381
|
-
*/
|
|
382
|
-
async deleteSponsorBlock() {
|
|
383
|
-
return this.node.deleteSponsorBlock(this);
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
*
|
|
387
|
-
* @param query Query for your data
|
|
388
|
-
* @param requestUser
|
|
389
|
-
*/
|
|
390
|
-
async search(query, requestUser, throwOnEmpty = false) {
|
|
391
|
-
const Query = this.LavalinkManager.utils.transformQuery(query);
|
|
392
|
-
if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) {
|
|
393
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
394
|
-
this.LavalinkManager.emit("debug", DebugEvents.BandcampSearchLokalEngine, {
|
|
395
|
-
state: "log",
|
|
396
|
-
message: `Player.search was called with a Bandcamp Query, but no bandcamp search was enabled on lavalink, searching with the custom Search Engine.`,
|
|
397
|
-
functionLayer: "Player > search()",
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
return await bandCampSearch(this, Query.query, requestUser);
|
|
401
|
-
}
|
|
402
|
-
return this.node.search(Query, requestUser, throwOnEmpty);
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Pause the player
|
|
406
|
-
*/
|
|
407
|
-
async pause() {
|
|
408
|
-
if (this.paused && !this.playing)
|
|
409
|
-
throw new Error("Player is already paused - not able to pause.");
|
|
410
|
-
this.paused = true;
|
|
411
|
-
this.lastPositionChange = null; // needs to removed to not cause issues
|
|
412
|
-
const now = performance.now();
|
|
413
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
|
|
414
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
415
|
-
// emit the event
|
|
416
|
-
this.LavalinkManager.emit("playerPaused", this, this.queue.current);
|
|
417
|
-
return this;
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Resume the Player
|
|
421
|
-
*/
|
|
422
|
-
async resume() {
|
|
423
|
-
if (!this.paused)
|
|
424
|
-
throw new Error("Player isn't paused - not able to resume.");
|
|
425
|
-
this.paused = false;
|
|
426
|
-
const now = performance.now();
|
|
427
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
|
|
428
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
429
|
-
// emit the event
|
|
430
|
-
this.LavalinkManager.emit("playerResumed", this, this.queue.current);
|
|
431
|
-
return this;
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Seek to a specific Position
|
|
435
|
-
* @param position
|
|
436
|
-
*/
|
|
437
|
-
async seek(position) {
|
|
438
|
-
if (!this.queue.current)
|
|
439
|
-
return undefined;
|
|
440
|
-
position = Number(position);
|
|
441
|
-
if (isNaN(position))
|
|
442
|
-
throw new RangeError("Position must be a number.");
|
|
443
|
-
if (!this.queue.current.info.isSeekable || this.queue.current.info.isStream)
|
|
444
|
-
throw new RangeError("Current Track is not seekable / a stream");
|
|
445
|
-
if (position < 0 || position > this.queue.current.info.duration)
|
|
446
|
-
position = Math.max(Math.min(position, this.queue.current.info.duration), 0);
|
|
447
|
-
this.lastPositionChange = Date.now();
|
|
448
|
-
this.lastPosition = position;
|
|
449
|
-
const now = performance.now();
|
|
450
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { position } });
|
|
451
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
452
|
-
return this;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Set the Repeatmode of the Player
|
|
456
|
-
* @param repeatMode
|
|
457
|
-
*/
|
|
458
|
-
async setRepeatMode(repeatMode) {
|
|
459
|
-
if (!["off", "track", "queue"].includes(repeatMode))
|
|
460
|
-
throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
|
|
461
|
-
this.repeatMode = repeatMode;
|
|
462
|
-
return this;
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Skip the current song, or a specific amount of songs
|
|
466
|
-
* @param amount provide the index of the next track to skip to
|
|
467
|
-
*/
|
|
468
|
-
async skip(skipTo = 0, throwError = true) {
|
|
469
|
-
if (!this.queue.tracks.length && (throwError || (typeof skipTo === "boolean" && skipTo === true)))
|
|
470
|
-
throw new RangeError("Can't skip more than the queue size");
|
|
471
|
-
if (typeof skipTo === "number" && skipTo > 1) {
|
|
472
|
-
if (skipTo > this.queue.tracks.length)
|
|
473
|
-
throw new RangeError("Can't skip more than the queue size");
|
|
474
|
-
await this.queue.splice(0, skipTo - 1);
|
|
475
|
-
}
|
|
476
|
-
if (!this.playing && !this.queue.current)
|
|
477
|
-
return (this.play(), this);
|
|
478
|
-
const now = performance.now();
|
|
479
|
-
this.set("internal_skipped", true);
|
|
480
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null }, paused: false } });
|
|
481
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
482
|
-
return this;
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Clears the queue and stops playing. Does not destroy the Player and not leave the channel
|
|
486
|
-
* @returns
|
|
487
|
-
*/
|
|
488
|
-
async stopPlaying(clearQueue = true, executeAutoplay = false) {
|
|
489
|
-
// use internal_stopPlaying on true, so that it doesn't utilize current loop states. on trackEnd event
|
|
490
|
-
this.set("internal_stopPlaying", true);
|
|
491
|
-
// remove tracks from the queue
|
|
492
|
-
if (this.queue.tracks.length && clearQueue === true)
|
|
493
|
-
await this.queue.splice(0, this.queue.tracks.length);
|
|
494
|
-
if (executeAutoplay === false)
|
|
495
|
-
this.set("internal_autoplayStopPlaying", true);
|
|
496
|
-
else
|
|
497
|
-
this.set("internal_autoplayStopPlaying", undefined);
|
|
498
|
-
const now = performance.now();
|
|
499
|
-
// send to lavalink, that it should stop playing
|
|
500
|
-
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null } } });
|
|
501
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
502
|
-
return this;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Connects the Player to the Voice Channel
|
|
506
|
-
* @returns
|
|
507
|
-
*/
|
|
508
|
-
async connect() {
|
|
509
|
-
if (!this.options.voiceChannelId)
|
|
510
|
-
throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
|
|
511
|
-
await this.LavalinkManager.options.sendToShard(this.guildId, {
|
|
512
|
-
op: 4,
|
|
513
|
-
d: {
|
|
514
|
-
guild_id: this.guildId,
|
|
515
|
-
channel_id: this.options.voiceChannelId,
|
|
516
|
-
self_mute: this.options.selfMute ?? false,
|
|
517
|
-
self_deaf: this.options.selfDeaf ?? true,
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
this.voiceChannelId = this.options.voiceChannelId;
|
|
521
|
-
return this;
|
|
522
|
-
}
|
|
523
|
-
async changeVoiceState(data) {
|
|
524
|
-
if (this.options.voiceChannelId === data.voiceChannelId)
|
|
525
|
-
throw new RangeError("New Channel can't be equal to the old Channel.");
|
|
526
|
-
await this.LavalinkManager.options.sendToShard(this.guildId, {
|
|
527
|
-
op: 4,
|
|
528
|
-
d: {
|
|
529
|
-
guild_id: this.guildId,
|
|
530
|
-
channel_id: data.voiceChannelId,
|
|
531
|
-
self_mute: data.selfMute ?? this.options.selfMute ?? false,
|
|
532
|
-
self_deaf: data.selfDeaf ?? this.options.selfDeaf ?? true,
|
|
533
|
-
}
|
|
534
|
-
});
|
|
535
|
-
// override the options
|
|
536
|
-
this.options.voiceChannelId = data.voiceChannelId;
|
|
537
|
-
this.options.selfMute = data.selfMute;
|
|
538
|
-
this.options.selfDeaf = data.selfDeaf;
|
|
539
|
-
this.voiceChannelId = data.voiceChannelId;
|
|
540
|
-
return this;
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Disconnects the Player from the Voice Channel, but keeps the player in the cache
|
|
544
|
-
* @param force If false it throws an error, if player thinks it's already disconnected
|
|
545
|
-
* @returns
|
|
546
|
-
*/
|
|
547
|
-
async disconnect(force = false) {
|
|
548
|
-
if (!force && !this.options.voiceChannelId)
|
|
549
|
-
throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
|
|
550
|
-
await this.LavalinkManager.options.sendToShard(this.guildId, {
|
|
551
|
-
op: 4,
|
|
552
|
-
d: {
|
|
553
|
-
guild_id: this.guildId,
|
|
554
|
-
channel_id: null,
|
|
555
|
-
self_mute: false,
|
|
556
|
-
self_deaf: false,
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
this.voiceChannelId = null;
|
|
560
|
-
return this;
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Destroy the player and disconnect from the voice channel
|
|
564
|
-
*/
|
|
565
|
-
async destroy(reason, disconnect = true) {
|
|
566
|
-
if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
|
|
567
|
-
console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`);
|
|
568
|
-
if (this.get("internal_queueempty")) {
|
|
569
|
-
clearTimeout(this.get("internal_queueempty"));
|
|
570
|
-
this.set("internal_queueempty", undefined);
|
|
571
|
-
}
|
|
572
|
-
if (this.get("internal_destroystatus") === true) {
|
|
573
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
574
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerDestroyingSomewhereElse, {
|
|
575
|
-
state: "warn",
|
|
576
|
-
message: `Player is already destroying somewhere else..`,
|
|
577
|
-
functionLayer: "Player > destroy()",
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
|
|
581
|
-
console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Already destroying somewhere else..`);
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
this.set("internal_destroystatus", true);
|
|
585
|
-
// disconnect player and set VoiceChannel to Null
|
|
586
|
-
if (disconnect)
|
|
587
|
-
await this.disconnect(true);
|
|
588
|
-
else
|
|
589
|
-
this.set("internal_destroywithoutdisconnect", true);
|
|
590
|
-
// Destroy the queue
|
|
591
|
-
await this.queue.utils.destroy();
|
|
592
|
-
// delete the player from cache
|
|
593
|
-
this.LavalinkManager.deletePlayer(this.guildId);
|
|
594
|
-
// destroy the player on lavalink side
|
|
595
|
-
await this.node.destroyPlayer(this.guildId);
|
|
596
|
-
if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
|
|
597
|
-
console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Player got destroyed successfully`);
|
|
598
|
-
// emit the event
|
|
599
|
-
this.LavalinkManager.emit("playerDestroy", this, reason);
|
|
600
|
-
// return smt
|
|
601
|
-
return this;
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Get the current lyrics of the track currently playing on the guild
|
|
605
|
-
* @param guildId The guild id to get the current lyrics for
|
|
606
|
-
* @param skipTrackSource If true, it will not try to get the lyrics from the track source
|
|
607
|
-
* @returns The current lyrics
|
|
608
|
-
* @example
|
|
609
|
-
* ```ts
|
|
610
|
-
* const lyrics = await player.getCurrentLyrics();
|
|
611
|
-
* ```
|
|
612
|
-
*/
|
|
613
|
-
async getCurrentLyrics(skipTrackSource) {
|
|
614
|
-
return await this.node.lyrics.getCurrent(this.guildId, skipTrackSource);
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Get the lyrics of a specific track
|
|
618
|
-
* @param track The track to get the lyrics for
|
|
619
|
-
* @param skipTrackSource If true, it will not try to get the lyrics from the track source
|
|
620
|
-
* @returns The lyrics of the track
|
|
621
|
-
* @example
|
|
622
|
-
* ```ts
|
|
623
|
-
* const lyrics = await player.getLyrics(player.queue.tracks[0], true);
|
|
624
|
-
* ```
|
|
625
|
-
*/
|
|
626
|
-
async getLyrics(track, skipTrackSource) {
|
|
627
|
-
return await this.node.lyrics.get(track, skipTrackSource);
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Subscribe to the lyrics event on a specific guild to active live lyrics events
|
|
631
|
-
* @returns The unsubscribe function
|
|
632
|
-
* @example
|
|
633
|
-
* ```ts
|
|
634
|
-
* const lyrics = await player.subscribeLyrics();
|
|
635
|
-
* ```
|
|
636
|
-
*/
|
|
637
|
-
subscribeLyrics() {
|
|
638
|
-
return this.node.lyrics.subscribe(this.guildId);
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Unsubscribe from the lyrics event on a specific guild to disable live lyrics events
|
|
642
|
-
* @returns The unsubscribe function
|
|
643
|
-
* @example
|
|
644
|
-
* ```ts
|
|
645
|
-
* const lyrics = await player.unsubscribeLyrics();
|
|
646
|
-
* ```
|
|
647
|
-
*/
|
|
648
|
-
unsubscribeLyrics() {
|
|
649
|
-
return this.node.lyrics.unsubscribe(this.guildId);
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Move the player on a different Audio-Node
|
|
653
|
-
* @param newNode New Node / New Node Id
|
|
654
|
-
* @param checkSources If it should check if the sources are supported by the new node
|
|
655
|
-
*/
|
|
656
|
-
async changeNode(newNode, checkSources = true) {
|
|
657
|
-
const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
|
|
658
|
-
if (!updateNode)
|
|
659
|
-
throw new Error("Could not find the new Node");
|
|
660
|
-
if (!updateNode.connected)
|
|
661
|
-
throw new Error("The provided Node is not active or disconnected");
|
|
662
|
-
if (this.node.id === updateNode.id)
|
|
663
|
-
throw new Error("Player is already on the provided Node");
|
|
664
|
-
if (this.get("internal_nodeChanging") === true)
|
|
665
|
-
throw new Error("Player is already changing the node please wait");
|
|
666
|
-
if (checkSources) {
|
|
667
|
-
const isDefaultSource = () => {
|
|
668
|
-
try {
|
|
669
|
-
this.LavalinkManager.utils.validateSourceString(updateNode, this.LavalinkManager.options.playerOptions.defaultSearchPlatform);
|
|
670
|
-
return true;
|
|
671
|
-
}
|
|
672
|
-
catch {
|
|
673
|
-
return false;
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
if (!isDefaultSource())
|
|
677
|
-
throw new RangeError(`defaultSearchPlatform "${this.LavalinkManager.options.playerOptions.defaultSearchPlatform}" is not supported by the newNode`);
|
|
678
|
-
if (this.queue.current || this.queue.tracks.length) { // Check if all queued track sources are supported by the new node
|
|
679
|
-
const trackSources = new Set([this.queue.current, ...this.queue.tracks].map(track => track.info.sourceName));
|
|
680
|
-
const missingSources = [...trackSources].filter(source => !updateNode.info.sourceManagers.includes(source));
|
|
681
|
-
if (missingSources.length)
|
|
682
|
-
throw new RangeError(`Sources missing for Node ${updateNode.id}: ${missingSources.join(', ')}`);
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
686
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
|
|
687
|
-
state: "log",
|
|
688
|
-
message: `Player.changeNode() was executed, trying to change from "${this.node.id}" to "${updateNode.id}"`,
|
|
689
|
-
functionLayer: "Player > changeNode()",
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
const data = this.toJSON();
|
|
693
|
-
const currentTrack = this.queue.current;
|
|
694
|
-
const segments = await this.getSponsorBlock().catch(() => []);
|
|
695
|
-
const voiceData = this.voice;
|
|
696
|
-
if (!voiceData.endpoint ||
|
|
697
|
-
!voiceData.sessionId ||
|
|
698
|
-
!voiceData.token)
|
|
699
|
-
throw new Error("Voice Data is missing, can't change the node");
|
|
700
|
-
this.set("internal_nodeChanging", true); // This will stop execution of trackEnd or queueEnd event while changing the node
|
|
701
|
-
if (this.node.connected)
|
|
702
|
-
await this.node.destroyPlayer(this.guildId); // destroy the player on the currentNode if it's connected
|
|
703
|
-
this.node = updateNode;
|
|
704
|
-
const now = performance.now();
|
|
705
|
-
try {
|
|
706
|
-
await this.connect();
|
|
707
|
-
const endpoint = `/sessions/${this.node.sessionId}/players/${this.guildId}`; //Send the VoiceData to the newly connected node.
|
|
708
|
-
await this.node.request(endpoint, r => {
|
|
709
|
-
r.method = "PATCH";
|
|
710
|
-
r.headers["Content-Type"] = "application/json";
|
|
711
|
-
r.body = safeStringify({
|
|
712
|
-
voice: {
|
|
713
|
-
token: voiceData.token,
|
|
714
|
-
endpoint: voiceData.endpoint,
|
|
715
|
-
sessionId: voiceData.sessionId
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
});
|
|
719
|
-
const hasSponsorBlock = this.node.info?.plugins?.find(v => v.name === "sponsorblock-plugin");
|
|
720
|
-
if (hasSponsorBlock) {
|
|
721
|
-
if (segments.length) {
|
|
722
|
-
await this.setSponsorBlock(segments).catch(error => {
|
|
723
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
724
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
|
|
725
|
-
state: "error",
|
|
726
|
-
error: error,
|
|
727
|
-
message: `Player > changeNode() Unable to set SponsorBlock Segments`,
|
|
728
|
-
functionLayer: "Player > changeNode()",
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
});
|
|
732
|
-
}
|
|
733
|
-
else {
|
|
734
|
-
await this.setSponsorBlock().catch(error => {
|
|
735
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
736
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
|
|
737
|
-
state: "error",
|
|
738
|
-
error: error,
|
|
739
|
-
message: `Player > changeNode() Unable to set SponsorBlock Segments`,
|
|
740
|
-
functionLayer: "Player > changeNode()",
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
if (currentTrack) { // If there is a current track, send it to the new node.
|
|
747
|
-
await this.node.updatePlayer({
|
|
748
|
-
guildId: this.guildId,
|
|
749
|
-
noReplace: false,
|
|
750
|
-
playerOptions: {
|
|
751
|
-
track: currentTrack ?? null,
|
|
752
|
-
position: currentTrack ? data.position : 0,
|
|
753
|
-
volume: data.lavalinkVolume,
|
|
754
|
-
paused: data.paused,
|
|
755
|
-
//filters: { ...data.filters, equalizer: data.equalizer }, Sending filters on nodeChange causes issues (player gets dicsonnected)
|
|
756
|
-
}
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
|
-
this.paused = data.paused;
|
|
760
|
-
this.playing = data.playing;
|
|
761
|
-
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
762
|
-
return this.node.id;
|
|
763
|
-
}
|
|
764
|
-
catch (error) {
|
|
765
|
-
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
766
|
-
this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
|
|
767
|
-
state: "error",
|
|
768
|
-
error: error,
|
|
769
|
-
message: `Player.changeNode() execution failed`,
|
|
770
|
-
functionLayer: "Player > changeNode()",
|
|
771
|
-
});
|
|
772
|
-
}
|
|
773
|
-
throw new Error(`Failed to change the node: ${error}`);
|
|
774
|
-
}
|
|
775
|
-
finally {
|
|
776
|
-
this.set("internal_nodeChanging", undefined);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
/** Converts the Player including Queue to a Json state */
|
|
780
|
-
toJSON() {
|
|
781
|
-
return {
|
|
782
|
-
guildId: this.guildId,
|
|
783
|
-
options: this.options,
|
|
784
|
-
voiceChannelId: this.voiceChannelId,
|
|
785
|
-
textChannelId: this.textChannelId,
|
|
786
|
-
position: this.position,
|
|
787
|
-
lastPosition: this.lastPosition,
|
|
788
|
-
lastPositionChange: this.lastPositionChange,
|
|
789
|
-
volume: this.volume,
|
|
790
|
-
lavalinkVolume: this.lavalinkVolume,
|
|
791
|
-
repeatMode: this.repeatMode,
|
|
792
|
-
paused: this.paused,
|
|
793
|
-
playing: this.playing,
|
|
794
|
-
createdTimeStamp: this.createdTimeStamp,
|
|
795
|
-
filters: this.filterManager?.data || {},
|
|
796
|
-
equalizer: this.filterManager?.equalizerBands || [],
|
|
797
|
-
nodeId: this.node?.id,
|
|
798
|
-
nodeSessionId: this.node?.sessionId,
|
|
799
|
-
ping: this.ping,
|
|
800
|
-
queue: this.queue.utils.toJSON(),
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
}
|