lavalink-client 2.3.0 → 2.3.3
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 +31 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/structures/Constants.d.ts +44 -1
- package/dist/cjs/structures/Constants.js +45 -1
- package/dist/cjs/structures/LavalinkManager.js +80 -5
- package/dist/cjs/structures/Node.js +202 -20
- package/dist/cjs/structures/Player.d.ts +0 -1
- package/dist/cjs/structures/Player.js +73 -6
- package/dist/cjs/structures/Queue.js +29 -2
- package/dist/cjs/structures/Types/Manager.d.ts +25 -0
- package/dist/cjs/structures/Types/Queue.d.ts +1 -1
- package/dist/cjs/structures/Utils.js +68 -18
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/structures/Constants.d.ts +44 -1
- package/dist/esm/structures/Constants.js +44 -0
- package/dist/esm/structures/LavalinkManager.js +81 -6
- package/dist/esm/structures/Node.js +203 -21
- package/dist/esm/structures/Player.d.ts +0 -1
- package/dist/esm/structures/Player.js +73 -6
- package/dist/esm/structures/Queue.js +29 -2
- package/dist/esm/structures/Types/Manager.d.ts +25 -0
- package/dist/esm/structures/Types/Queue.d.ts +1 -1
- package/dist/esm/structures/Utils.js +68 -18
- package/dist/types/index.d.ts +1 -0
- package/dist/types/structures/Constants.d.ts +44 -1
- package/dist/types/structures/Player.d.ts +0 -1
- package/dist/types/structures/Types/Manager.d.ts +25 -0
- package/dist/types/structures/Types/Queue.d.ts +1 -1
- package/package.json +1 -1
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -13
- package/dist/structures/Filters.d.ts +0 -230
- package/dist/structures/Filters.js +0 -472
- package/dist/structures/LavalinkManager.d.ts +0 -47
- package/dist/structures/LavalinkManager.js +0 -36
- package/dist/structures/LavalinkManagerStatics.d.ts +0 -3
- package/dist/structures/LavalinkManagerStatics.js +0 -76
- package/dist/structures/Node.d.ts +0 -171
- package/dist/structures/Node.js +0 -462
- package/dist/structures/NodeManager.d.ts +0 -58
- package/dist/structures/NodeManager.js +0 -25
- package/dist/structures/Player.d.ts +0 -101
- package/dist/structures/Player.js +0 -232
- package/dist/structures/PlayerManager.d.ts +0 -62
- package/dist/structures/PlayerManager.js +0 -26
- package/dist/structures/Queue.d.ts +0 -93
- package/dist/structures/Queue.js +0 -160
- package/dist/structures/QueueManager.d.ts +0 -77
- package/dist/structures/QueueManager.js +0 -74
- package/dist/structures/Track.d.ts +0 -27
- package/dist/structures/Track.js +0 -2
- package/dist/structures/Utils.d.ts +0 -183
- package/dist/structures/Utils.js +0 -43
|
@@ -192,7 +192,8 @@ class LavalinkNode {
|
|
|
192
192
|
}
|
|
193
193
|
let uri = `/loadtracks?identifier=`;
|
|
194
194
|
if (/^https?:\/\//.test(Query.query) || ["http", "https", "link", "uri"].includes(Query.source)) { // if it's a link simply encode it
|
|
195
|
-
|
|
195
|
+
const url = encodeURIComponent(Query.query);
|
|
196
|
+
uri += url;
|
|
196
197
|
}
|
|
197
198
|
else { // if not make a query out of it
|
|
198
199
|
if (Query.source !== "local")
|
|
@@ -209,8 +210,16 @@ class LavalinkNode {
|
|
|
209
210
|
});
|
|
210
211
|
// transform the data which can be Error, Track or Track[] to enfore [Track]
|
|
211
212
|
const resTracks = res.loadType === "playlist" ? res.data?.tracks : res.loadType === "track" ? [res.data] : res.loadType === "search" ? Array.isArray(res.data) ? res.data : [res.data] : [];
|
|
212
|
-
if (throwOnEmpty === true && (res.loadType === "empty" || !resTracks.length))
|
|
213
|
+
if (throwOnEmpty === true && (res.loadType === "empty" || !resTracks.length)) {
|
|
214
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
215
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.SearchNothingFound, {
|
|
216
|
+
state: "warn",
|
|
217
|
+
message: `Search found nothing for Request: "${Query.source ? `${Query.source}:` : ""}${Query.query}"`,
|
|
218
|
+
functionLayer: "(LavalinkNode > node | player) > search()",
|
|
219
|
+
});
|
|
220
|
+
}
|
|
213
221
|
throw new Error("Nothing found");
|
|
222
|
+
}
|
|
214
223
|
return {
|
|
215
224
|
loadType: res.loadType,
|
|
216
225
|
exception: res.loadType === "error" ? res.data : null,
|
|
@@ -254,8 +263,16 @@ class LavalinkNode {
|
|
|
254
263
|
throw new RangeError(`there is no lavasrc-plugin available in the lavalink node: ${this.id}`);
|
|
255
264
|
const { request } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
|
|
256
265
|
const res = (request.status === 204 ? {} : await request.json());
|
|
257
|
-
if (throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length)
|
|
266
|
+
if (throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length) {
|
|
267
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
268
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.LavaSearchNothingFound, {
|
|
269
|
+
state: "warn",
|
|
270
|
+
message: `LavaSearch found nothing for Request: "${Query.source ? `${Query.source}:` : ""}${Query.query}"`,
|
|
271
|
+
functionLayer: "(LavalinkNode > node | player) > lavaSearch()",
|
|
272
|
+
});
|
|
273
|
+
}
|
|
258
274
|
throw new Error("Nothing found");
|
|
275
|
+
}
|
|
259
276
|
return {
|
|
260
277
|
tracks: res.tracks?.map(v => this.NodeManager.LavalinkManager.utils.buildTrack(v, requestUser)) || [],
|
|
261
278
|
albums: res.albums?.map(v => ({ info: v.info, pluginInfo: v?.plugin || v.pluginInfo, tracks: v.tracks.map(v => this.NodeManager.LavalinkManager.utils.buildTrack(v, requestUser)) })) || [],
|
|
@@ -291,6 +308,13 @@ class LavalinkNode {
|
|
|
291
308
|
r.path = url.pathname + url.search;
|
|
292
309
|
}
|
|
293
310
|
});
|
|
311
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
312
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerUpdateSuccess, {
|
|
313
|
+
state: "log",
|
|
314
|
+
message: `Player get's updated with following payload :: ${JSON.stringify(data.playerOptions, null, 3)}`,
|
|
315
|
+
functionLayer: "LavalinkNode > node > updatePlayer()",
|
|
316
|
+
});
|
|
317
|
+
}
|
|
294
318
|
return this.syncPlayerData({}, res), res;
|
|
295
319
|
}
|
|
296
320
|
/**
|
|
@@ -323,8 +347,16 @@ class LavalinkNode {
|
|
|
323
347
|
* ```
|
|
324
348
|
*/
|
|
325
349
|
connect(sessionId) {
|
|
326
|
-
if (this.connected)
|
|
350
|
+
if (this.connected) {
|
|
351
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
352
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TryingConnectWhileConnected, {
|
|
353
|
+
state: "warn",
|
|
354
|
+
message: `Tryed to connect to node, but it's already connected!`,
|
|
355
|
+
functionLayer: "LavalinkNode > node > connect()",
|
|
356
|
+
});
|
|
357
|
+
}
|
|
327
358
|
return;
|
|
359
|
+
}
|
|
328
360
|
const headers = {
|
|
329
361
|
Authorization: this.options.authorization,
|
|
330
362
|
"User-Id": this.NodeManager.LavalinkManager.options.client.id,
|
|
@@ -342,11 +374,33 @@ class LavalinkNode {
|
|
|
342
374
|
// this.socket.on("ping", () => this.heartBeat("ping")); // lavalink doesn'T send ping periodically, therefore we use the stats message
|
|
343
375
|
}
|
|
344
376
|
heartBeat() {
|
|
377
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
378
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.HeartBeatTriggered, {
|
|
379
|
+
state: "log",
|
|
380
|
+
message: `Node Socket Heartbeat triggered, resetting old Timeout to 65000ms (should happen every 60s due to /stats event)`,
|
|
381
|
+
functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat()",
|
|
382
|
+
});
|
|
383
|
+
}
|
|
345
384
|
if (this.pingTimeout)
|
|
346
385
|
clearTimeout(this.pingTimeout);
|
|
347
386
|
this.pingTimeout = setTimeout(() => {
|
|
348
|
-
if (!this.socket)
|
|
349
|
-
|
|
387
|
+
if (!this.socket) {
|
|
388
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
389
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.NoSocketOnDestroy, {
|
|
390
|
+
state: "error",
|
|
391
|
+
message: `Heartbeat registered a disconnect, but socket didn't exist therefore can't terminate`,
|
|
392
|
+
functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat() > timeoutHit",
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
398
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.SocketTerminateHeartBeatTimeout, {
|
|
399
|
+
state: "warn",
|
|
400
|
+
message: `Heartbeat registered a disconnect, because timeout wasn't resetted in time. Terminating Web-Socket`,
|
|
401
|
+
functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat() > timeoutHit",
|
|
402
|
+
});
|
|
403
|
+
}
|
|
350
404
|
this.isAlive = false;
|
|
351
405
|
this.socket.terminate();
|
|
352
406
|
}, 65000); // the stats endpoint get's sent every 60s. se wee add a 5s buffer to make sure we don't miss any stats message
|
|
@@ -838,8 +892,16 @@ class LavalinkNode {
|
|
|
838
892
|
case "playerUpdate":
|
|
839
893
|
{
|
|
840
894
|
const player = this.NodeManager.LavalinkManager.getPlayer(payload.guildId);
|
|
841
|
-
if (!player)
|
|
895
|
+
if (!player) {
|
|
896
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
897
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerUpdateNoPlayer, {
|
|
898
|
+
state: "error",
|
|
899
|
+
message: `PlayerUpdate Event Triggered, but no player found of payload.guildId: ${payload.guildId}`,
|
|
900
|
+
functionLayer: "LavalinkNode > nodeEvent > playerUpdate",
|
|
901
|
+
});
|
|
902
|
+
}
|
|
842
903
|
return;
|
|
904
|
+
}
|
|
843
905
|
const oldPlayer = player?.toJSON();
|
|
844
906
|
player.lastPositionChange = Date.now();
|
|
845
907
|
player.lastPosition = payload.state.position || 0;
|
|
@@ -849,6 +911,13 @@ class LavalinkNode {
|
|
|
849
911
|
player.createdTimeStamp = payload.state.time;
|
|
850
912
|
if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600000) || (0, path_1.isAbsolute)(player.queue.current?.info?.uri))) {
|
|
851
913
|
player.filterManager.filterUpdatedState = false;
|
|
914
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
915
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerUpdateFilterFixApply, {
|
|
916
|
+
state: "log",
|
|
917
|
+
message: `Fixing FilterState on "${player.guildId}" because player.options.instaUpdateFiltersFix === true`,
|
|
918
|
+
functionLayer: "LavalinkNode > nodeEvent > playerUpdate",
|
|
919
|
+
});
|
|
920
|
+
}
|
|
852
921
|
await player.seek(player.position);
|
|
853
922
|
}
|
|
854
923
|
this.NodeManager.LavalinkManager.emit("playerUpdate", oldPlayer, player);
|
|
@@ -865,7 +934,14 @@ class LavalinkNode {
|
|
|
865
934
|
this.NodeManager.emit("resumed", this, payload, await this.fetchAllPlayers());
|
|
866
935
|
}
|
|
867
936
|
catch (e) {
|
|
868
|
-
|
|
937
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
938
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.ResumingFetchingError, {
|
|
939
|
+
state: "error",
|
|
940
|
+
message: `Failed to fetch players for resumed event, falling back without players array`,
|
|
941
|
+
error: e,
|
|
942
|
+
functionLayer: "LavalinkNode > nodeEvent > resumed",
|
|
943
|
+
});
|
|
944
|
+
}
|
|
869
945
|
this.NodeManager.emit("resumed", this, payload, []);
|
|
870
946
|
}
|
|
871
947
|
}
|
|
@@ -926,12 +1002,30 @@ class LavalinkNode {
|
|
|
926
1002
|
player.playing = true;
|
|
927
1003
|
player.paused = false;
|
|
928
1004
|
// don't emit the event if previous track == new track aka track loop
|
|
929
|
-
if (this.NodeManager.LavalinkManager.options?.emitNewSongsOnly === true && player.queue.previous[0]?.info?.identifier === track?.info?.identifier)
|
|
1005
|
+
if (this.NodeManager.LavalinkManager.options?.emitNewSongsOnly === true && player.queue.previous[0]?.info?.identifier === track?.info?.identifier) {
|
|
1006
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1007
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackStartNewSongsOnly, {
|
|
1008
|
+
state: "log",
|
|
1009
|
+
message: `TrackStart not Emitting, because playing the previous song again.`,
|
|
1010
|
+
functionLayer: "LavalinkNode > trackStart()",
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
930
1013
|
return;
|
|
1014
|
+
}
|
|
931
1015
|
if (!player.queue.current) {
|
|
932
1016
|
player.queue.current = await this.getTrackOfPayload(payload);
|
|
933
|
-
if (player.queue.current)
|
|
1017
|
+
if (player.queue.current) {
|
|
934
1018
|
await player.queue.utils.save();
|
|
1019
|
+
}
|
|
1020
|
+
else {
|
|
1021
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1022
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackStartNoTrack, {
|
|
1023
|
+
state: "warn",
|
|
1024
|
+
message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`,
|
|
1025
|
+
functionLayer: "LavalinkNode > trackStart()",
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
935
1029
|
}
|
|
936
1030
|
return this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload);
|
|
937
1031
|
}
|
|
@@ -940,6 +1034,13 @@ class LavalinkNode {
|
|
|
940
1034
|
const trackToUse = track || await this.getTrackOfPayload(payload);
|
|
941
1035
|
// If a track was forcibly played
|
|
942
1036
|
if (payload.reason === "replaced") {
|
|
1037
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1038
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackEndReplaced, {
|
|
1039
|
+
state: "warn",
|
|
1040
|
+
message: `TrackEnd Event does not handle any playback, because the track was replaced.`,
|
|
1041
|
+
functionLayer: "LavalinkNode > trackEnd()",
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
943
1044
|
return this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
944
1045
|
}
|
|
945
1046
|
// If there are no songs in the queue
|
|
@@ -965,10 +1066,10 @@ class LavalinkNode {
|
|
|
965
1066
|
player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
|
|
966
1067
|
await player.queue.utils.save();
|
|
967
1068
|
}
|
|
968
|
-
player.set("internal_skipped", false);
|
|
969
1069
|
// if no track available, end queue
|
|
970
1070
|
if (!player.queue.current)
|
|
971
1071
|
return this.queueEnd(player, trackToUse, payload);
|
|
1072
|
+
player.set("internal_skipped", false);
|
|
972
1073
|
// fire event
|
|
973
1074
|
this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload);
|
|
974
1075
|
// play track if autoSkip is true
|
|
@@ -976,6 +1077,21 @@ class LavalinkNode {
|
|
|
976
1077
|
}
|
|
977
1078
|
/** @private util function for handling trackStuck event */
|
|
978
1079
|
async trackStuck(player, track, payload) {
|
|
1080
|
+
if (this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) {
|
|
1081
|
+
const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || [])
|
|
1082
|
+
.filter(v => Date.now() - v < this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold);
|
|
1083
|
+
player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
|
|
1084
|
+
if (oldTimestamps.length > this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
|
|
1085
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1086
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackStuckMaxTracksErroredPerTime, {
|
|
1087
|
+
state: "log",
|
|
1088
|
+
message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
1089
|
+
functionLayer: "LavalinkNode > trackStuck()",
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
return player.destroy(Constants_1.DestroyReasons.TrackStuckMaxTracksErroredPerTime);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
979
1095
|
this.NodeManager.LavalinkManager.emit("trackStuck", player, track || await this.getTrackOfPayload(payload), payload);
|
|
980
1096
|
// If there are no songs in the queue
|
|
981
1097
|
if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
|
|
@@ -983,13 +1099,29 @@ class LavalinkNode {
|
|
|
983
1099
|
// remove the current track, and enqueue the next one
|
|
984
1100
|
await (0, Utils_1.queueTrackEnd)(player);
|
|
985
1101
|
// if no track available, end queue
|
|
986
|
-
if (!player.queue.current)
|
|
1102
|
+
if (!player.queue.current) {
|
|
987
1103
|
return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload);
|
|
1104
|
+
}
|
|
988
1105
|
// play track if autoSkip is true
|
|
989
1106
|
return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true });
|
|
990
1107
|
}
|
|
991
1108
|
/** @private util function for handling trackError event */
|
|
992
1109
|
async trackError(player, track, payload) {
|
|
1110
|
+
if (this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) {
|
|
1111
|
+
const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || [])
|
|
1112
|
+
.filter(v => Date.now() - v < this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold);
|
|
1113
|
+
player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
|
|
1114
|
+
if (oldTimestamps.length > this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
|
|
1115
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1116
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TrackErrorMaxTracksErroredPerTime, {
|
|
1117
|
+
state: "log",
|
|
1118
|
+
message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
1119
|
+
functionLayer: "LavalinkNode > trackError()",
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
return player.destroy(Constants_1.DestroyReasons.TrackErrorMaxTracksErroredPerTime);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
993
1125
|
this.NodeManager.LavalinkManager.emit("trackError", player, track || await this.getTrackOfPayload(payload), payload);
|
|
994
1126
|
return; // get's handled by trackEnd
|
|
995
1127
|
// If there are no songs in the queue
|
|
@@ -1073,6 +1205,13 @@ class LavalinkNode {
|
|
|
1073
1205
|
r.headers = { Authorization: this.options.authorization, 'Content-Type': 'application/json' };
|
|
1074
1206
|
r.body = JSON.stringify(segments.map(v => v.toLowerCase()));
|
|
1075
1207
|
});
|
|
1208
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1209
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.SetSponsorBlock, {
|
|
1210
|
+
state: "log",
|
|
1211
|
+
message: `SponsorBlock was set for Player: ${player.guildId} to: ${segments.map(v => `'${v.toLowerCase()}'`).join(", ")}`,
|
|
1212
|
+
functionLayer: "LavalinkNode > setSponsorBlock()",
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1076
1215
|
return;
|
|
1077
1216
|
}
|
|
1078
1217
|
/**
|
|
@@ -1094,6 +1233,13 @@ class LavalinkNode {
|
|
|
1094
1233
|
await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, (r) => {
|
|
1095
1234
|
r.method = "DELETE";
|
|
1096
1235
|
});
|
|
1236
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1237
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.DeleteSponsorBlock, {
|
|
1238
|
+
state: "log",
|
|
1239
|
+
message: `SponsorBlock was deleted for Player: ${player.guildId}`,
|
|
1240
|
+
functionLayer: "LavalinkNode > deleteSponsorBlock()",
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1097
1243
|
return;
|
|
1098
1244
|
}
|
|
1099
1245
|
/** private util function for handling the queue end event */
|
|
@@ -1102,17 +1248,46 @@ class LavalinkNode {
|
|
|
1102
1248
|
player.queue.current = null;
|
|
1103
1249
|
player.playing = false;
|
|
1104
1250
|
player.set("internal_stopPlaying", undefined);
|
|
1251
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1252
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.QueueEnded, {
|
|
1253
|
+
state: "log",
|
|
1254
|
+
message: `Queue Ended because no more Tracks were in the Queue, due to EventName: "${payload.type}"`,
|
|
1255
|
+
functionLayer: "LavalinkNode > queueEnd()",
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1105
1258
|
if (typeof this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function" && typeof player.get("internal_autoplayStopPlaying") === "undefined") {
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1259
|
+
const previousAutoplayTime = player.get("internal_previousautoplay");
|
|
1260
|
+
const duration = previousAutoplayTime ? Date.now() - previousAutoplayTime : 0;
|
|
1261
|
+
if ((duration && duration > this.NodeManager.LavalinkManager.options.playerOptions.minAutoPlayMs) || !!player.get("internal_skipped")) {
|
|
1262
|
+
await this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track);
|
|
1263
|
+
player.set("internal_previousautoplay", Date.now());
|
|
1264
|
+
if (player.queue.tracks.length > 0)
|
|
1265
|
+
await (0, Utils_1.queueTrackEnd)(player);
|
|
1266
|
+
else if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1267
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.AutoplayNoSongsAdded, {
|
|
1268
|
+
state: "warn",
|
|
1269
|
+
message: `Autoplay was triggered but no songs were added to the queue.`,
|
|
1270
|
+
functionLayer: "LavalinkNode > queueEnd() > autoplayFunction",
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
if (player.queue.current) {
|
|
1274
|
+
if (payload.type === "TrackEndEvent")
|
|
1275
|
+
this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
|
|
1276
|
+
return player.play({ noReplace: true, paused: false });
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
else {
|
|
1280
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1281
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.AutoplayThresholdSpamLimiter, {
|
|
1282
|
+
state: "warn",
|
|
1283
|
+
message: `Autoplay was triggered after the previousautoplay too early. Threshold is: ${this.NodeManager.LavalinkManager.options.playerOptions.minAutoPlayMs}ms and the Duration was ${duration}ms`,
|
|
1284
|
+
functionLayer: "LavalinkNode > queueEnd() > autoplayFunction",
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1113
1287
|
}
|
|
1114
1288
|
}
|
|
1115
|
-
player.set("
|
|
1289
|
+
player.set("internal_skipped", false);
|
|
1290
|
+
player.set("internal_autoplayStopPlaying", Date.now());
|
|
1116
1291
|
if (track && !track?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
|
|
1117
1292
|
player.queue.previous.unshift(track);
|
|
1118
1293
|
if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
|
|
@@ -1126,6 +1301,13 @@ class LavalinkNode {
|
|
|
1126
1301
|
if (this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0)
|
|
1127
1302
|
return player.destroy(Constants_1.DestroyReasons.QueueEmpty);
|
|
1128
1303
|
else {
|
|
1304
|
+
if (this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
1305
|
+
this.NodeManager.LavalinkManager.emit("debug", Constants_1.DebugEvents.TriggerQueueEmptyInterval, {
|
|
1306
|
+
state: "log",
|
|
1307
|
+
message: `Trigger Queue Empty Interval was Triggered because playerOptions.onEmptyQueue.destroyAfterMs is set to ${this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs}ms`,
|
|
1308
|
+
functionLayer: "LavalinkNode > queueEnd() > destroyAfterMs",
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1129
1311
|
if (player.get("internal_queueempty")) {
|
|
1130
1312
|
clearTimeout(player.get("internal_queueempty"));
|
|
1131
1313
|
player.set("internal_queueempty", undefined);
|
|
@@ -134,7 +134,6 @@ export declare class Player {
|
|
|
134
134
|
* @param repeatMode
|
|
135
135
|
*/
|
|
136
136
|
setRepeatMode(repeatMode: RepeatMode): Promise<this>;
|
|
137
|
-
1: any;
|
|
138
137
|
/**
|
|
139
138
|
* Skip the current song, or a specific amount of songs
|
|
140
139
|
* @param amount provide the index of the next track to skip to
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Player = void 0;
|
|
4
|
+
const Constants_1 = require("./Constants");
|
|
4
5
|
const BandCampSearch_1 = require("./CustomSearches/BandCampSearch");
|
|
5
6
|
const Filters_1 = require("./Filters");
|
|
6
7
|
const Queue_1 = require("./Queue");
|
|
@@ -72,8 +73,17 @@ class Player {
|
|
|
72
73
|
this.guildId = this.options.guildId;
|
|
73
74
|
this.voiceChannelId = this.options.voiceChannelId;
|
|
74
75
|
this.textChannelId = this.options.textChannelId || null;
|
|
75
|
-
this.node = typeof this.options.node === "string"
|
|
76
|
+
this.node = typeof this.options.node === "string"
|
|
77
|
+
? this.LavalinkManager.nodeManager.nodes.get(this.options.node)
|
|
78
|
+
: this.options.node;
|
|
76
79
|
if (!this.node || typeof this.node.request !== "function") {
|
|
80
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
81
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerCreateNodeNotFound, {
|
|
82
|
+
state: "warn",
|
|
83
|
+
message: `Player was created with provided node Id: ${this.options.node}, but no node with that Id was found.`,
|
|
84
|
+
functionLayer: "Player > constructor()",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
77
87
|
const least = this.LavalinkManager.nodeManager.leastUsedNodes();
|
|
78
88
|
this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
|
|
79
89
|
}
|
|
@@ -128,6 +138,13 @@ class Player {
|
|
|
128
138
|
*/
|
|
129
139
|
async play(options = {}) {
|
|
130
140
|
if (this.get("internal_queueempty")) {
|
|
141
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
142
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayQueueEmptyTimeoutClear, {
|
|
143
|
+
state: "log",
|
|
144
|
+
message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`,
|
|
145
|
+
functionLayer: "Player > play()",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
131
148
|
clearTimeout(this.get("internal_queueempty"));
|
|
132
149
|
this.set("internal_queueempty", undefined);
|
|
133
150
|
}
|
|
@@ -168,6 +185,13 @@ class Player {
|
|
|
168
185
|
...(track.userData || {}),
|
|
169
186
|
requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {})
|
|
170
187
|
};
|
|
188
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
189
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayWithTrackReplace, {
|
|
190
|
+
state: "log",
|
|
191
|
+
message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`,
|
|
192
|
+
functionLayer: "Player > play()",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
171
195
|
return this.node.updatePlayer({
|
|
172
196
|
guildId: this.guildId,
|
|
173
197
|
noReplace: false,
|
|
@@ -185,6 +209,13 @@ class Player {
|
|
|
185
209
|
if (!this.queue.current && this.queue.tracks.length)
|
|
186
210
|
await (0, Utils_1.queueTrackEnd)(this);
|
|
187
211
|
if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
|
|
212
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
213
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayUnresolvedTrack, {
|
|
214
|
+
state: "log",
|
|
215
|
+
message: `Player Play was called, current Queue Song is unresolved, resolving the track.`,
|
|
216
|
+
functionLayer: "Player > play()",
|
|
217
|
+
});
|
|
218
|
+
}
|
|
188
219
|
try {
|
|
189
220
|
// resolve the unresolved track
|
|
190
221
|
await this.queue.current.resolve(this);
|
|
@@ -192,6 +223,14 @@ class Player {
|
|
|
192
223
|
this.queue.current.userData = { ...(this.queue.current?.userData || {}), ...(options.track?.userData || {}) };
|
|
193
224
|
}
|
|
194
225
|
catch (error) {
|
|
226
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
227
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerPlayUnresolvedTrackFailed, {
|
|
228
|
+
state: "error",
|
|
229
|
+
error: error,
|
|
230
|
+
message: `Player Play was called, current Queue Song is unresolved, but couldn't resolve it`,
|
|
231
|
+
functionLayer: "Player > play() > resolve currentTrack",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
195
234
|
this.LavalinkManager.emit("trackError", this, this.queue.current, error);
|
|
196
235
|
if (options && "clientTrack" in options)
|
|
197
236
|
delete options.clientTrack;
|
|
@@ -258,6 +297,13 @@ class Player {
|
|
|
258
297
|
: this.volume), 1000), 0));
|
|
259
298
|
const now = performance.now();
|
|
260
299
|
if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
|
|
300
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
301
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerVolumeAsFilter, {
|
|
302
|
+
state: "log",
|
|
303
|
+
message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`,
|
|
304
|
+
functionLayer: "Player > setVolume()",
|
|
305
|
+
});
|
|
306
|
+
}
|
|
261
307
|
await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
|
|
262
308
|
}
|
|
263
309
|
else {
|
|
@@ -302,8 +348,16 @@ class Player {
|
|
|
302
348
|
*/
|
|
303
349
|
async search(query, requestUser, throwOnEmpty = false) {
|
|
304
350
|
const Query = this.LavalinkManager.utils.transformQuery(query);
|
|
305
|
-
if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp"))
|
|
351
|
+
if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) {
|
|
352
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
353
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.BandcampSearchLokalEngine, {
|
|
354
|
+
state: "log",
|
|
355
|
+
message: `Player.search was called with a Bandcamp Query, but no bandcamp search was enabled on lavalink, searching with the custom Search Engine.`,
|
|
356
|
+
functionLayer: "Player > search()",
|
|
357
|
+
});
|
|
358
|
+
}
|
|
306
359
|
return await (0, BandCampSearch_1.bandCampSearch)(this, Query.query, requestUser);
|
|
360
|
+
}
|
|
307
361
|
return this.node.search(Query, requestUser, throwOnEmpty);
|
|
308
362
|
}
|
|
309
363
|
/**
|
|
@@ -362,7 +416,6 @@ class Player {
|
|
|
362
416
|
this.repeatMode = repeatMode;
|
|
363
417
|
return this;
|
|
364
418
|
}
|
|
365
|
-
1;
|
|
366
419
|
/**
|
|
367
420
|
* Skip the current song, or a specific amount of songs
|
|
368
421
|
* @param amount provide the index of the next track to skip to
|
|
@@ -468,6 +521,13 @@ class Player {
|
|
|
468
521
|
if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
|
|
469
522
|
console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`);
|
|
470
523
|
if (this.get("internal_destroystatus") === true) {
|
|
524
|
+
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
525
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerDestroyingSomewhereElse, {
|
|
526
|
+
state: "warn",
|
|
527
|
+
message: `Player is already destroying somewhere else..`,
|
|
528
|
+
functionLayer: "Player > destroy()",
|
|
529
|
+
});
|
|
530
|
+
}
|
|
471
531
|
if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
|
|
472
532
|
console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Already destroying somewhere else..`);
|
|
473
533
|
return;
|
|
@@ -499,10 +559,19 @@ class Player {
|
|
|
499
559
|
const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
|
|
500
560
|
if (!updateNode)
|
|
501
561
|
throw new Error("Could not find the new Node");
|
|
562
|
+
if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
|
|
563
|
+
this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerChangeNode, {
|
|
564
|
+
state: "log",
|
|
565
|
+
message: `Player.changeNode() was executed, trying to change from "${this.node.id}" to "${updateNode.id}"`,
|
|
566
|
+
functionLayer: "Player > changeNode()",
|
|
567
|
+
});
|
|
568
|
+
}
|
|
502
569
|
const data = this.toJSON();
|
|
570
|
+
const currentTrack = this.queue.current;
|
|
503
571
|
await this.node.destroyPlayer(this.guildId);
|
|
504
572
|
this.node = updateNode;
|
|
505
573
|
const now = performance.now();
|
|
574
|
+
await this.connect();
|
|
506
575
|
await this.node.updatePlayer({
|
|
507
576
|
guildId: this.guildId,
|
|
508
577
|
noReplace: false,
|
|
@@ -511,9 +580,7 @@ class Player {
|
|
|
511
580
|
volume: Math.round(Math.max(Math.min(data.volume, 1000), 0)),
|
|
512
581
|
paused: data.paused,
|
|
513
582
|
filters: { ...data.filters, equalizer: data.equalizer },
|
|
514
|
-
|
|
515
|
-
track: this.queue.current ?? undefined
|
|
516
|
-
// track: this.queue.current,
|
|
583
|
+
track: currentTrack ?? undefined
|
|
517
584
|
},
|
|
518
585
|
});
|
|
519
586
|
this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
|
|
@@ -291,11 +291,18 @@ class Queue {
|
|
|
291
291
|
* ```
|
|
292
292
|
*/
|
|
293
293
|
async remove(removeQueryTrack) {
|
|
294
|
+
const oldStored = typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
|
|
294
295
|
if (typeof removeQueryTrack === "number") {
|
|
295
296
|
const toRemove = this.tracks[removeQueryTrack];
|
|
296
297
|
if (!toRemove)
|
|
297
298
|
return null;
|
|
298
299
|
const removed = this.tracks.splice(removeQueryTrack, 1);
|
|
300
|
+
// Log if available
|
|
301
|
+
if (typeof this.queueChanges?.tracksRemoved === "function")
|
|
302
|
+
try {
|
|
303
|
+
this.queueChanges.tracksRemoved(this.guildId, removed, removeQueryTrack, oldStored, this.utils.toJSON());
|
|
304
|
+
}
|
|
305
|
+
catch (e) { /* */ }
|
|
299
306
|
await this.utils.save();
|
|
300
307
|
return { removed };
|
|
301
308
|
}
|
|
@@ -303,11 +310,18 @@ class Queue {
|
|
|
303
310
|
if (removeQueryTrack.every(v => typeof v === "number")) {
|
|
304
311
|
const removed = [];
|
|
305
312
|
for (const i of removeQueryTrack) {
|
|
306
|
-
if (this.tracks[i])
|
|
313
|
+
if (this.tracks[i]) {
|
|
307
314
|
removed.push(...this.tracks.splice(i, 1));
|
|
315
|
+
}
|
|
308
316
|
}
|
|
309
317
|
if (!removed.length)
|
|
310
318
|
return null;
|
|
319
|
+
// Log if available
|
|
320
|
+
if (typeof this.queueChanges?.tracksRemoved === "function")
|
|
321
|
+
try {
|
|
322
|
+
this.queueChanges.tracksRemoved(this.guildId, removed, removeQueryTrack, oldStored, this.utils.toJSON());
|
|
323
|
+
}
|
|
324
|
+
catch (e) { /* */ }
|
|
311
325
|
await this.utils.save();
|
|
312
326
|
return { removed };
|
|
313
327
|
}
|
|
@@ -322,9 +336,16 @@ class Queue {
|
|
|
322
336
|
return null;
|
|
323
337
|
const removed = [];
|
|
324
338
|
for (const { i } of tracksToRemove) {
|
|
325
|
-
if (this.tracks[i])
|
|
339
|
+
if (this.tracks[i]) {
|
|
326
340
|
removed.push(...this.tracks.splice(i, 1));
|
|
341
|
+
}
|
|
327
342
|
}
|
|
343
|
+
// Log if available
|
|
344
|
+
if (typeof this.queueChanges?.tracksRemoved === "function")
|
|
345
|
+
try {
|
|
346
|
+
this.queueChanges.tracksRemoved(this.guildId, removed, tracksToRemove.map(v => v.i), oldStored, this.utils.toJSON());
|
|
347
|
+
}
|
|
348
|
+
catch (e) { /* */ }
|
|
328
349
|
await this.utils.save();
|
|
329
350
|
return { removed };
|
|
330
351
|
}
|
|
@@ -337,6 +358,12 @@ class Queue {
|
|
|
337
358
|
if (toRemove < 0)
|
|
338
359
|
return null;
|
|
339
360
|
const removed = this.tracks.splice(toRemove, 1);
|
|
361
|
+
// Log if available
|
|
362
|
+
if (typeof this.queueChanges?.tracksRemoved === "function")
|
|
363
|
+
try {
|
|
364
|
+
this.queueChanges.tracksRemoved(this.guildId, removed, toRemove, oldStored, this.utils.toJSON());
|
|
365
|
+
}
|
|
366
|
+
catch (e) { /* */ }
|
|
340
367
|
await this.utils.save();
|
|
341
368
|
return { removed };
|
|
342
369
|
}
|