lavalink-client 2.11.0 → 2.11.1
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 +2 -0
- package/dist/index.cjs +70 -27
- package/dist/index.d.cts +15 -6
- package/dist/index.d.mts +15 -6
- package/dist/index.d.ts +15 -6
- package/dist/index.js +70 -27
- package/dist/index.mjs +70 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -414,6 +414,8 @@ This client powers various Discord bots:
|
|
|
414
414
|
- [BeatDock](https://github.com/lazaroagomez/BeatDock) (@lazaroagomez)
|
|
415
415
|
- [Nazha](https://top.gg/bot/1124681788070055967) (@Nazha-Team)
|
|
416
416
|
- [Arii Music](https://arimusic.me/) (@friston_ae)
|
|
417
|
+
- [Listen](https://listen.ac) (@gabcaua)
|
|
418
|
+
- [NOTHING](https://discord.com/discovery/applications/1234592539324059709) (@ankush.ly)
|
|
417
419
|
|
|
418
420
|
---
|
|
419
421
|
|
package/dist/index.cjs
CHANGED
|
@@ -1247,8 +1247,8 @@ var ManagerUtils = class {
|
|
|
1247
1247
|
* @returns
|
|
1248
1248
|
*/
|
|
1249
1249
|
isTrack(data) {
|
|
1250
|
-
if (!data) return false;
|
|
1251
|
-
if (data
|
|
1250
|
+
if (!data || typeof data !== "object") return false;
|
|
1251
|
+
if (Reflect.get(data, TrackSymbol) === true) return true;
|
|
1252
1252
|
return typeof data?.encoded === "string" && typeof data?.info === "object" && !("resolve" in data);
|
|
1253
1253
|
}
|
|
1254
1254
|
/**
|
|
@@ -1257,7 +1257,7 @@ var ManagerUtils = class {
|
|
|
1257
1257
|
*/
|
|
1258
1258
|
isUnresolvedTrack(data) {
|
|
1259
1259
|
if (!data) return false;
|
|
1260
|
-
if (data
|
|
1260
|
+
if (Reflect.get(data, UnresolvedTrackSymbol) === true) return true;
|
|
1261
1261
|
return typeof data === "object" && ("info" in data && typeof data.info.title === "string" || typeof data.encoded === "string") && "resolve" in data && typeof data.resolve === "function";
|
|
1262
1262
|
}
|
|
1263
1263
|
/**
|
|
@@ -1298,7 +1298,7 @@ var ManagerUtils = class {
|
|
|
1298
1298
|
if (node._checkForSources && !node.info.sourceManagers?.length) throw new Error("Lavalink Node, has no sourceManagers enabled");
|
|
1299
1299
|
if (!queryString.trim().length) throw new Error(`Query string is empty, please provide a valid query string.`);
|
|
1300
1300
|
if (sourceString === "speak" && queryString.length > 100) throw new Error(`Query is speak, which is limited to 100 characters.`);
|
|
1301
|
-
if (this.LavalinkManager.options?.linksBlacklist
|
|
1301
|
+
if (this.LavalinkManager?.options?.linksBlacklist && this.LavalinkManager.options?.linksBlacklist.length > 0) {
|
|
1302
1302
|
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) this.LavalinkManager.emit("debug", "ValidatingBlacklistLinks", {
|
|
1303
1303
|
state: "log",
|
|
1304
1304
|
message: `Validating Query against LavalinkManager.options.linksBlacklist, query: "${queryString}"`,
|
|
@@ -1307,9 +1307,9 @@ var ManagerUtils = class {
|
|
|
1307
1307
|
if (this.LavalinkManager.options?.linksBlacklist.some((v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || (0, node_util_types.isRegExp)(v) && v.test(queryString))) throw new Error(`Query string contains a link / word which is blacklisted.`);
|
|
1308
1308
|
}
|
|
1309
1309
|
if (!/^https?:\/\//.test(queryString)) return;
|
|
1310
|
-
else if (this.LavalinkManager
|
|
1311
|
-
if (this.LavalinkManager.options?.linksWhitelist
|
|
1312
|
-
if (this.LavalinkManager
|
|
1310
|
+
else if (this.LavalinkManager?.options?.linksAllowed === false) throw new Error("Using links to make a request is not allowed.");
|
|
1311
|
+
if (this.LavalinkManager?.options?.linksWhitelist && this.LavalinkManager.options?.linksWhitelist.length > 0) {
|
|
1312
|
+
if (this.LavalinkManager?.options?.advancedOptions?.enableDebugEvents) this.LavalinkManager.emit("debug", "ValidatingWhitelistLinks", {
|
|
1313
1313
|
state: "log",
|
|
1314
1314
|
message: `Link was provided to the Query, validating against LavalinkManager.options.linksWhitelist, query: "${queryString}"`,
|
|
1315
1315
|
functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()"
|
|
@@ -1433,7 +1433,7 @@ var ManagerUtils = class {
|
|
|
1433
1433
|
validateSourceString(node, sourceString) {
|
|
1434
1434
|
if (!sourceString) throw new Error(`No SourceString was provided`);
|
|
1435
1435
|
const source = this.SourcesRecord[sourceString.toLowerCase().trim()];
|
|
1436
|
-
if (!source &&
|
|
1436
|
+
if (!source && !this.LavalinkManager.options.playerOptions.allowCustomSources) throw new Error(`Lavalink-Client does not support SearchQuerySource: '${sourceString}'. You can disable this check by setting 'ManagerOptions.PlayerOptions.allowCustomSources' to true`);
|
|
1437
1437
|
if (!node.info) throw new Error("Lavalink Node does not have any info cached yet, not ready yet!");
|
|
1438
1438
|
if (!node._checkForSources) return;
|
|
1439
1439
|
if (source === "amsearch" && !node.info?.sourceManagers?.includes("applemusic")) throw new Error("Lavalink Node has not 'applemusic' enabled, which is required to have 'amsearch' work");
|
|
@@ -1994,7 +1994,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
1994
1994
|
this.sessionId = this.options.sessionId || sessionId;
|
|
1995
1995
|
}
|
|
1996
1996
|
this.socket = new ws.default(`ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`, { headers });
|
|
1997
|
-
this.socket.on("open", this.open.
|
|
1997
|
+
this.socket.on("open", () => void this.open().catch((error) => {
|
|
1998
|
+
this.error(error);
|
|
1999
|
+
}));
|
|
1998
2000
|
this.socket.on("close", (code, reason) => void this.close(code, reason?.toString()).catch((error) => {
|
|
1999
2001
|
this.NodeManager.emit("error", this, error);
|
|
2000
2002
|
}));
|
|
@@ -2854,7 +2856,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
2854
2856
|
const player = this._LManager.getPlayer(data.guildId);
|
|
2855
2857
|
if (!player) return;
|
|
2856
2858
|
if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false) {
|
|
2857
|
-
player.destroy("LavalinkNoVoice")
|
|
2859
|
+
player.destroy("LavalinkNoVoice").catch((error) => {
|
|
2860
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
2861
|
+
});
|
|
2858
2862
|
return;
|
|
2859
2863
|
}
|
|
2860
2864
|
player.ping.ws = res?.voice?.ping || player?.ping.ws;
|
|
@@ -3153,11 +3157,12 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3153
3157
|
player.playing = true;
|
|
3154
3158
|
player.paused = false;
|
|
3155
3159
|
}
|
|
3156
|
-
if (this._LManager.options?.emitNewSongsOnly === true && player.
|
|
3160
|
+
if (this._LManager.options?.emitNewSongsOnly === true && player.getData("internal_lastEmittedTrackId") === track?.info?.identifier) return this._emitDebugEvent("TrackStartNewSongsOnly", {
|
|
3157
3161
|
state: "log",
|
|
3158
3162
|
message: `TrackStart not Emitting, because playing the previous song again.`,
|
|
3159
3163
|
functionLayer: "LavalinkNode > trackStart()"
|
|
3160
3164
|
});
|
|
3165
|
+
player.setData("internal_lastEmittedTrackId", track?.info?.identifier);
|
|
3161
3166
|
if (!player.queue.current) {
|
|
3162
3167
|
player.queue.current = this.getTrackOfPayload(payload);
|
|
3163
3168
|
if (player.queue.current) await player.queue.utils.save();
|
|
@@ -3179,6 +3184,7 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3179
3184
|
message: `TrackEnd Event does not handle any playback, because the track was replaced.`,
|
|
3180
3185
|
functionLayer: "LavalinkNode > trackEnd()"
|
|
3181
3186
|
});
|
|
3187
|
+
player.setData("internal_lastEmittedTrackId", void 0);
|
|
3182
3188
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3183
3189
|
return;
|
|
3184
3190
|
}
|
|
@@ -3188,7 +3194,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3188
3194
|
await queueTrackEnd(player);
|
|
3189
3195
|
if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
|
|
3190
3196
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3191
|
-
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true })
|
|
3197
|
+
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true }).catch((error) => {
|
|
3198
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3199
|
+
});
|
|
3192
3200
|
return;
|
|
3193
3201
|
}
|
|
3194
3202
|
if (player.repeatMode !== "track" || player.getData("internal_skipped")) await queueTrackEnd(player);
|
|
@@ -3200,7 +3208,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3200
3208
|
if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
|
|
3201
3209
|
player.setData("internal_skipped", false);
|
|
3202
3210
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3203
|
-
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true })
|
|
3211
|
+
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true }).catch((error) => {
|
|
3212
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3213
|
+
});
|
|
3204
3214
|
}
|
|
3205
3215
|
/** @private util function for handling trackStuck event */
|
|
3206
3216
|
async trackStuck(player, track, payload) {
|
|
@@ -3213,7 +3223,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3213
3223
|
message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
3214
3224
|
functionLayer: "LavalinkNode > trackStuck()"
|
|
3215
3225
|
});
|
|
3216
|
-
player.destroy("TrackStuckMaxTracksErroredPerTime")
|
|
3226
|
+
player.destroy("TrackStuckMaxTracksErroredPerTime").catch((error) => {
|
|
3227
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3228
|
+
});
|
|
3217
3229
|
return;
|
|
3218
3230
|
}
|
|
3219
3231
|
}
|
|
@@ -3232,6 +3244,8 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3232
3244
|
if (this._LManager.options.autoSkip && player.queue.current) player.play({
|
|
3233
3245
|
track: player.queue.current,
|
|
3234
3246
|
noReplace: false
|
|
3247
|
+
}).catch((error) => {
|
|
3248
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3235
3249
|
});
|
|
3236
3250
|
}
|
|
3237
3251
|
/** @private util function for handling trackError event */
|
|
@@ -3245,7 +3259,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3245
3259
|
message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
3246
3260
|
functionLayer: "LavalinkNode > trackError()"
|
|
3247
3261
|
});
|
|
3248
|
-
player.destroy("TrackErrorMaxTracksErroredPerTime")
|
|
3262
|
+
player.destroy("TrackErrorMaxTracksErroredPerTime").catch((error) => {
|
|
3263
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3264
|
+
});
|
|
3249
3265
|
return;
|
|
3250
3266
|
}
|
|
3251
3267
|
}
|
|
@@ -3345,6 +3361,7 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3345
3361
|
player.queue.current = null;
|
|
3346
3362
|
player.playing = false;
|
|
3347
3363
|
player.setData("internal_stopPlaying", void 0);
|
|
3364
|
+
player.setData("internal_lastEmittedTrackId", void 0);
|
|
3348
3365
|
this._emitDebugEvent("QueueEnded", {
|
|
3349
3366
|
state: "log",
|
|
3350
3367
|
message: `Queue Ended because no more Tracks were in the Queue, due to EventName: "${payload.type}"`,
|
|
@@ -3373,6 +3390,8 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3373
3390
|
if (this._LManager.options.autoSkip) return player.play({
|
|
3374
3391
|
noReplace: true,
|
|
3375
3392
|
paused: false
|
|
3393
|
+
}).catch((error) => {
|
|
3394
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3376
3395
|
});
|
|
3377
3396
|
} else this._emitDebugEvent("AutoplayThresholdSpamLimiter", {
|
|
3378
3397
|
state: "warn",
|
|
@@ -3390,7 +3409,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3390
3409
|
if (payload?.reason !== "stopped") await player.queue.utils.save();
|
|
3391
3410
|
if (typeof this._LManager.options.playerOptions?.onEmptyQueue?.destroyAfterMs === "number" && !isNaN(this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs) && this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs >= 0) {
|
|
3392
3411
|
if (this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) {
|
|
3393
|
-
player.destroy("QueueEmpty")
|
|
3412
|
+
player.destroy("QueueEmpty").catch((error) => {
|
|
3413
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3414
|
+
});
|
|
3394
3415
|
return;
|
|
3395
3416
|
} else {
|
|
3396
3417
|
this._emitDebugEvent("TriggerQueueEmptyInterval", {
|
|
@@ -3404,7 +3425,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3404
3425
|
player.setData("internal_queueempty", void 0);
|
|
3405
3426
|
if (player.queue.current) return this._LManager.emit("playerQueueEmptyCancel", player);
|
|
3406
3427
|
this._LManager.emit("playerQueueEmptyEnd", player);
|
|
3407
|
-
player.destroy("QueueEmpty")
|
|
3428
|
+
player.destroy("QueueEmpty").catch((error) => {
|
|
3429
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3430
|
+
});
|
|
3408
3431
|
}, this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
|
|
3409
3432
|
}
|
|
3410
3433
|
}
|
|
@@ -5018,6 +5041,14 @@ var FilterManager = class {
|
|
|
5018
5041
|
|
|
5019
5042
|
//#endregion
|
|
5020
5043
|
//#region src/structures/Queue.ts
|
|
5044
|
+
function tracksMatch(a, b) {
|
|
5045
|
+
if (a === b) return true;
|
|
5046
|
+
if (a.encoded) return a.encoded === b.encoded;
|
|
5047
|
+
if (a.info?.identifier) return a.info.identifier === b.info?.identifier;
|
|
5048
|
+
if (a.info?.uri) return a.info.uri === b.info?.uri;
|
|
5049
|
+
if (a.info?.isrc) return a.info.isrc === b.info?.isrc;
|
|
5050
|
+
return a.info?.title && a.info.title === b.info?.title || a.info?.artworkUrl && a.info.artworkUrl === b.info?.artworkUrl || false;
|
|
5051
|
+
}
|
|
5021
5052
|
var QueueSaver = class {
|
|
5022
5053
|
/**
|
|
5023
5054
|
* The queue store manager
|
|
@@ -5148,14 +5179,14 @@ var Queue = class {
|
|
|
5148
5179
|
*/
|
|
5149
5180
|
save: async () => {
|
|
5150
5181
|
if (this.previous.length > this.options.maxPreviousTracks) this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
5151
|
-
return await this.QueueSaver
|
|
5182
|
+
return await this.QueueSaver?.set(this.guildId, this.utils.toJSON());
|
|
5152
5183
|
},
|
|
5153
5184
|
/**
|
|
5154
5185
|
* Sync the current queue database/server with the cached one
|
|
5155
5186
|
* @returns {void}
|
|
5156
5187
|
*/
|
|
5157
5188
|
sync: async (override = true, dontSyncCurrent = true) => {
|
|
5158
|
-
const data = await this.QueueSaver
|
|
5189
|
+
const data = await this.QueueSaver?.get(this.guildId);
|
|
5159
5190
|
if (!data) throw new Error(`No data found to sync for guildId: ${this.guildId}`);
|
|
5160
5191
|
if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current)) this.current = data.current;
|
|
5161
5192
|
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track))) this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
@@ -5163,7 +5194,7 @@ var Queue = class {
|
|
|
5163
5194
|
await this.utils.save();
|
|
5164
5195
|
},
|
|
5165
5196
|
destroy: async () => {
|
|
5166
|
-
return await this.QueueSaver
|
|
5197
|
+
return await this.QueueSaver?.delete(this.guildId);
|
|
5167
5198
|
},
|
|
5168
5199
|
/**
|
|
5169
5200
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
|
|
@@ -5292,12 +5323,12 @@ var Queue = class {
|
|
|
5292
5323
|
* @param {number} index Where to remove the Track
|
|
5293
5324
|
* @param {number} amount How many Tracks to remove?
|
|
5294
5325
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
5295
|
-
* @returns {Track} Spliced Track
|
|
5326
|
+
* @returns {Track} Spliced (aka Removed) Track
|
|
5296
5327
|
*/
|
|
5297
5328
|
async splice(index, amount, TrackOrTracks) {
|
|
5298
5329
|
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
|
|
5299
5330
|
if (!this.tracks.length) {
|
|
5300
|
-
if (TrackOrTracks)
|
|
5331
|
+
if (TrackOrTracks) await this.add(TrackOrTracks);
|
|
5301
5332
|
return null;
|
|
5302
5333
|
}
|
|
5303
5334
|
if (TrackOrTracks && typeof this.queueChanges?.tracksAdd === "function") try {
|
|
@@ -5369,7 +5400,7 @@ var Queue = class {
|
|
|
5369
5400
|
const tracksToRemove = this.tracks.map((v, i) => ({
|
|
5370
5401
|
v,
|
|
5371
5402
|
i
|
|
5372
|
-
})).filter(({ v, i }) => removeQueryTrack.find((t) => typeof t === "number" && t === i || typeof t === "object" &&
|
|
5403
|
+
})).filter(({ v, i }) => removeQueryTrack.find((t) => typeof t === "number" && t === i || typeof t === "object" && t !== null && tracksMatch(t, v)));
|
|
5373
5404
|
if (!tracksToRemove.length) return null;
|
|
5374
5405
|
const removed = [];
|
|
5375
5406
|
tracksToRemove.sort((a, b) => b.i - a.i);
|
|
@@ -5380,7 +5411,7 @@ var Queue = class {
|
|
|
5380
5411
|
await this.utils.save();
|
|
5381
5412
|
return { removed };
|
|
5382
5413
|
}
|
|
5383
|
-
const toRemove = this.tracks.findIndex((v) => removeQueryTrack
|
|
5414
|
+
const toRemove = this.tracks.findIndex((v) => tracksMatch(removeQueryTrack, v));
|
|
5384
5415
|
if (toRemove < 0) return null;
|
|
5385
5416
|
const removed = this.tracks.splice(toRemove, 1);
|
|
5386
5417
|
if (typeof this.queueChanges?.tracksRemoved === "function") try {
|
|
@@ -5751,7 +5782,9 @@ var Player = class {
|
|
|
5751
5782
|
}
|
|
5752
5783
|
if (options?.track?.encoded || options?.track?.identifier) {
|
|
5753
5784
|
this.queue.current = options.clientTrack || null;
|
|
5754
|
-
this.queue.utils.save()
|
|
5785
|
+
this.queue.utils.save().catch((error) => {
|
|
5786
|
+
if (!this.LavalinkManager.options.catchLifeCycleRejections) throw error;
|
|
5787
|
+
});
|
|
5755
5788
|
if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
|
|
5756
5789
|
this.volume = Math.max(Math.min(options?.volume, 1e3), 0);
|
|
5757
5790
|
let vol = Number(this.volume);
|
|
@@ -6020,7 +6053,12 @@ var Player = class {
|
|
|
6020
6053
|
if (skipTo > this.queue.tracks.length) throw new RangeError("Can't skip more than the queue size");
|
|
6021
6054
|
await this.queue.splice(0, skipTo - 1);
|
|
6022
6055
|
}
|
|
6023
|
-
if (!this.playing && !this.queue.current)
|
|
6056
|
+
if (!this.playing && !this.queue.current) {
|
|
6057
|
+
this.play().catch((error) => {
|
|
6058
|
+
if (!this.LavalinkManager.options.catchLifeCycleRejections) throw error;
|
|
6059
|
+
});
|
|
6060
|
+
return this;
|
|
6061
|
+
}
|
|
6024
6062
|
const now = performance.now();
|
|
6025
6063
|
this.setData("internal_skipped", true);
|
|
6026
6064
|
await this.node.updatePlayer({
|
|
@@ -6231,6 +6269,7 @@ var Player = class {
|
|
|
6231
6269
|
const currentTrack = this.queue.current;
|
|
6232
6270
|
if (!this.voice.endpoint || !this.voice.sessionId || !this.voice.token) throw new Error("Voice Data is missing, can't change the node");
|
|
6233
6271
|
this.setData("internal_nodeChanging", true);
|
|
6272
|
+
this.setData("internal_lastEmittedTrackId", void 0);
|
|
6234
6273
|
if (this.node.connected) await this.node.destroyPlayer(this.guildId);
|
|
6235
6274
|
this.node = updateNode;
|
|
6236
6275
|
const now = performance.now();
|
|
@@ -6446,6 +6485,7 @@ var LavalinkManager = class LavalinkManager extends node_events.EventEmitter {
|
|
|
6446
6485
|
linksAllowed: options?.linksAllowed ?? true,
|
|
6447
6486
|
autoSkip: options?.autoSkip ?? true,
|
|
6448
6487
|
autoSkipOnResolveError: options?.autoSkipOnResolveError ?? true,
|
|
6488
|
+
catchLifeCycleRejections: options?.catchLifeCycleRejections ?? false,
|
|
6449
6489
|
emitNewSongsOnly: options?.emitNewSongsOnly ?? false,
|
|
6450
6490
|
queueOptions: {
|
|
6451
6491
|
maxPreviousTracks: options?.queueOptions?.maxPreviousTracks ?? 25,
|
|
@@ -6481,6 +6521,7 @@ var LavalinkManager = class LavalinkManager extends node_events.EventEmitter {
|
|
|
6481
6521
|
if (typeof options?.sendToShard !== "function") throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
|
|
6482
6522
|
if (options?.autoSkip && typeof options?.autoSkip !== "boolean") throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
|
|
6483
6523
|
if (options?.autoSkipOnResolveError && typeof options?.autoSkipOnResolveError !== "boolean") throw new SyntaxError("ManagerOption.autoSkipOnResolveError must be either false | true aka boolean");
|
|
6524
|
+
if (options?.catchLifeCycleRejections && typeof options?.catchLifeCycleRejections !== "boolean") throw new SyntaxError("ManagerOption.catchLifeCycleRejections must be either false | true aka boolean");
|
|
6484
6525
|
if (options?.emitNewSongsOnly && typeof options?.emitNewSongsOnly !== "boolean") throw new SyntaxError("ManagerOption.emitNewSongsOnly must be either false | true aka boolean");
|
|
6485
6526
|
if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every((node) => node instanceof NodeLinkNode || node instanceof LavalinkNode || this.utils.isNodeOptions(node))) throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions or the Node-Classes 'NodeLinkNode' or 'LavalinkNode' and is required of at least 1 Node");
|
|
6486
6527
|
if (options?.queueOptions?.queueStore) {
|
|
@@ -6788,7 +6829,9 @@ var LavalinkManager = class LavalinkManager extends node_events.EventEmitter {
|
|
|
6788
6829
|
const update = "d" in data ? data.d : data;
|
|
6789
6830
|
if (!update.guild_id) return;
|
|
6790
6831
|
const player = this.getPlayer(update.guild_id);
|
|
6791
|
-
if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted")
|
|
6832
|
+
if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted").catch((error) => {
|
|
6833
|
+
if (!this.options.catchLifeCycleRejections) throw error;
|
|
6834
|
+
});
|
|
6792
6835
|
}
|
|
6793
6836
|
if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
|
|
6794
6837
|
const update = "d" in data ? data.d : data;
|
package/dist/index.d.cts
CHANGED
|
@@ -668,7 +668,7 @@ declare class ManagerUtils {
|
|
|
668
668
|
* @param data the Track to validate
|
|
669
669
|
* @returns
|
|
670
670
|
*/
|
|
671
|
-
isTrack(data
|
|
671
|
+
isTrack(data?: Track | UnresolvedTrack | null): data is Track;
|
|
672
672
|
/**
|
|
673
673
|
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
674
674
|
* @param track
|
|
@@ -2342,13 +2342,13 @@ declare class Queue {
|
|
|
2342
2342
|
/**
|
|
2343
2343
|
* Save the current cached Queue on the database/server (overides the server)
|
|
2344
2344
|
*/
|
|
2345
|
-
save: () => Promise<void | boolean>;
|
|
2345
|
+
save: () => Promise<void | boolean | undefined>;
|
|
2346
2346
|
/**
|
|
2347
2347
|
* Sync the current queue database/server with the cached one
|
|
2348
2348
|
* @returns {void}
|
|
2349
2349
|
*/
|
|
2350
2350
|
sync: (override?: boolean, dontSyncCurrent?: boolean) => Promise<void>;
|
|
2351
|
-
destroy: () => Promise<void | boolean>;
|
|
2351
|
+
destroy: () => Promise<void | boolean | undefined>;
|
|
2352
2352
|
/**
|
|
2353
2353
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
|
|
2354
2354
|
*/
|
|
@@ -2441,15 +2441,15 @@ declare class Queue {
|
|
|
2441
2441
|
* @param {number} index At what position to add the Track
|
|
2442
2442
|
* @returns {number} Queue-Size (for the next Tracks)
|
|
2443
2443
|
*/
|
|
2444
|
-
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number):
|
|
2444
|
+
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): Promise<number | (Track | UnresolvedTrack)[] | Track | UnresolvedTrack | null>;
|
|
2445
2445
|
/**
|
|
2446
2446
|
* Splice the tracks in the Queue
|
|
2447
2447
|
* @param {number} index Where to remove the Track
|
|
2448
2448
|
* @param {number} amount How many Tracks to remove?
|
|
2449
2449
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
2450
|
-
* @returns {Track} Spliced Track
|
|
2450
|
+
* @returns {Track} Spliced (aka Removed) Track
|
|
2451
2451
|
*/
|
|
2452
|
-
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]):
|
|
2452
|
+
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): Promise<Track | UnresolvedTrack | (Track | UnresolvedTrack)[] | null>;
|
|
2453
2453
|
/**
|
|
2454
2454
|
* Remove stuff from the queue.tracks array
|
|
2455
2455
|
* - single Track | UnresolvedTrack
|
|
@@ -4089,6 +4089,15 @@ interface ManagerOptions<CustomPlayerT extends Player = Player> {
|
|
|
4089
4089
|
autoMove?: boolean;
|
|
4090
4090
|
/** If it should skip to the next Track if track.resolve errors while trying to play a track. */
|
|
4091
4091
|
autoSkipOnResolveError?: boolean;
|
|
4092
|
+
/**
|
|
4093
|
+
* If the library's internal fire-and-forget lifecycle calls (e.g. autoSkip `player.play()`,
|
|
4094
|
+
* `player.destroy()`, and the fire-and-forget queue `save()` inside `Player#play()`) should
|
|
4095
|
+
* catch their own rejections instead of letting them surface as unhandled rejections which
|
|
4096
|
+
* may crash the host application.
|
|
4097
|
+
* Default: false - rejections surface as unhandled rejections, exactly as if this option
|
|
4098
|
+
* did not exist.
|
|
4099
|
+
*/
|
|
4100
|
+
catchLifeCycleRejections?: boolean;
|
|
4092
4101
|
/** If it should emit only new (unique) songs and not when a looping track (or similar) is plaid, default false */
|
|
4093
4102
|
emitNewSongsOnly?: boolean;
|
|
4094
4103
|
/** Only allow link requests with links either matching some of that regExp or including some of that string */
|
package/dist/index.d.mts
CHANGED
|
@@ -668,7 +668,7 @@ declare class ManagerUtils {
|
|
|
668
668
|
* @param data the Track to validate
|
|
669
669
|
* @returns
|
|
670
670
|
*/
|
|
671
|
-
isTrack(data
|
|
671
|
+
isTrack(data?: Track | UnresolvedTrack | null): data is Track;
|
|
672
672
|
/**
|
|
673
673
|
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
674
674
|
* @param track
|
|
@@ -2342,13 +2342,13 @@ declare class Queue {
|
|
|
2342
2342
|
/**
|
|
2343
2343
|
* Save the current cached Queue on the database/server (overides the server)
|
|
2344
2344
|
*/
|
|
2345
|
-
save: () => Promise<void | boolean>;
|
|
2345
|
+
save: () => Promise<void | boolean | undefined>;
|
|
2346
2346
|
/**
|
|
2347
2347
|
* Sync the current queue database/server with the cached one
|
|
2348
2348
|
* @returns {void}
|
|
2349
2349
|
*/
|
|
2350
2350
|
sync: (override?: boolean, dontSyncCurrent?: boolean) => Promise<void>;
|
|
2351
|
-
destroy: () => Promise<void | boolean>;
|
|
2351
|
+
destroy: () => Promise<void | boolean | undefined>;
|
|
2352
2352
|
/**
|
|
2353
2353
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
|
|
2354
2354
|
*/
|
|
@@ -2441,15 +2441,15 @@ declare class Queue {
|
|
|
2441
2441
|
* @param {number} index At what position to add the Track
|
|
2442
2442
|
* @returns {number} Queue-Size (for the next Tracks)
|
|
2443
2443
|
*/
|
|
2444
|
-
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number):
|
|
2444
|
+
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): Promise<number | (Track | UnresolvedTrack)[] | Track | UnresolvedTrack | null>;
|
|
2445
2445
|
/**
|
|
2446
2446
|
* Splice the tracks in the Queue
|
|
2447
2447
|
* @param {number} index Where to remove the Track
|
|
2448
2448
|
* @param {number} amount How many Tracks to remove?
|
|
2449
2449
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
2450
|
-
* @returns {Track} Spliced Track
|
|
2450
|
+
* @returns {Track} Spliced (aka Removed) Track
|
|
2451
2451
|
*/
|
|
2452
|
-
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]):
|
|
2452
|
+
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): Promise<Track | UnresolvedTrack | (Track | UnresolvedTrack)[] | null>;
|
|
2453
2453
|
/**
|
|
2454
2454
|
* Remove stuff from the queue.tracks array
|
|
2455
2455
|
* - single Track | UnresolvedTrack
|
|
@@ -4089,6 +4089,15 @@ interface ManagerOptions<CustomPlayerT extends Player = Player> {
|
|
|
4089
4089
|
autoMove?: boolean;
|
|
4090
4090
|
/** If it should skip to the next Track if track.resolve errors while trying to play a track. */
|
|
4091
4091
|
autoSkipOnResolveError?: boolean;
|
|
4092
|
+
/**
|
|
4093
|
+
* If the library's internal fire-and-forget lifecycle calls (e.g. autoSkip `player.play()`,
|
|
4094
|
+
* `player.destroy()`, and the fire-and-forget queue `save()` inside `Player#play()`) should
|
|
4095
|
+
* catch their own rejections instead of letting them surface as unhandled rejections which
|
|
4096
|
+
* may crash the host application.
|
|
4097
|
+
* Default: false - rejections surface as unhandled rejections, exactly as if this option
|
|
4098
|
+
* did not exist.
|
|
4099
|
+
*/
|
|
4100
|
+
catchLifeCycleRejections?: boolean;
|
|
4092
4101
|
/** If it should emit only new (unique) songs and not when a looping track (or similar) is plaid, default false */
|
|
4093
4102
|
emitNewSongsOnly?: boolean;
|
|
4094
4103
|
/** Only allow link requests with links either matching some of that regExp or including some of that string */
|
package/dist/index.d.ts
CHANGED
|
@@ -668,7 +668,7 @@ declare class ManagerUtils {
|
|
|
668
668
|
* @param data the Track to validate
|
|
669
669
|
* @returns
|
|
670
670
|
*/
|
|
671
|
-
isTrack(data
|
|
671
|
+
isTrack(data?: Track | UnresolvedTrack | null): data is Track;
|
|
672
672
|
/**
|
|
673
673
|
* Checks if the provided argument is a valid UnresolvedTrack.
|
|
674
674
|
* @param track
|
|
@@ -2342,13 +2342,13 @@ declare class Queue {
|
|
|
2342
2342
|
/**
|
|
2343
2343
|
* Save the current cached Queue on the database/server (overides the server)
|
|
2344
2344
|
*/
|
|
2345
|
-
save: () => Promise<void | boolean>;
|
|
2345
|
+
save: () => Promise<void | boolean | undefined>;
|
|
2346
2346
|
/**
|
|
2347
2347
|
* Sync the current queue database/server with the cached one
|
|
2348
2348
|
* @returns {void}
|
|
2349
2349
|
*/
|
|
2350
2350
|
sync: (override?: boolean, dontSyncCurrent?: boolean) => Promise<void>;
|
|
2351
|
-
destroy: () => Promise<void | boolean>;
|
|
2351
|
+
destroy: () => Promise<void | boolean | undefined>;
|
|
2352
2352
|
/**
|
|
2353
2353
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
|
|
2354
2354
|
*/
|
|
@@ -2441,15 +2441,15 @@ declare class Queue {
|
|
|
2441
2441
|
* @param {number} index At what position to add the Track
|
|
2442
2442
|
* @returns {number} Queue-Size (for the next Tracks)
|
|
2443
2443
|
*/
|
|
2444
|
-
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number):
|
|
2444
|
+
add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): Promise<number | (Track | UnresolvedTrack)[] | Track | UnresolvedTrack | null>;
|
|
2445
2445
|
/**
|
|
2446
2446
|
* Splice the tracks in the Queue
|
|
2447
2447
|
* @param {number} index Where to remove the Track
|
|
2448
2448
|
* @param {number} amount How many Tracks to remove?
|
|
2449
2449
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
2450
|
-
* @returns {Track} Spliced Track
|
|
2450
|
+
* @returns {Track} Spliced (aka Removed) Track
|
|
2451
2451
|
*/
|
|
2452
|
-
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]):
|
|
2452
|
+
splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): Promise<Track | UnresolvedTrack | (Track | UnresolvedTrack)[] | null>;
|
|
2453
2453
|
/**
|
|
2454
2454
|
* Remove stuff from the queue.tracks array
|
|
2455
2455
|
* - single Track | UnresolvedTrack
|
|
@@ -4089,6 +4089,15 @@ interface ManagerOptions<CustomPlayerT extends Player = Player> {
|
|
|
4089
4089
|
autoMove?: boolean;
|
|
4090
4090
|
/** If it should skip to the next Track if track.resolve errors while trying to play a track. */
|
|
4091
4091
|
autoSkipOnResolveError?: boolean;
|
|
4092
|
+
/**
|
|
4093
|
+
* If the library's internal fire-and-forget lifecycle calls (e.g. autoSkip `player.play()`,
|
|
4094
|
+
* `player.destroy()`, and the fire-and-forget queue `save()` inside `Player#play()`) should
|
|
4095
|
+
* catch their own rejections instead of letting them surface as unhandled rejections which
|
|
4096
|
+
* may crash the host application.
|
|
4097
|
+
* Default: false - rejections surface as unhandled rejections, exactly as if this option
|
|
4098
|
+
* did not exist.
|
|
4099
|
+
*/
|
|
4100
|
+
catchLifeCycleRejections?: boolean;
|
|
4092
4101
|
/** If it should emit only new (unique) songs and not when a looping track (or similar) is plaid, default false */
|
|
4093
4102
|
emitNewSongsOnly?: boolean;
|
|
4094
4103
|
/** Only allow link requests with links either matching some of that regExp or including some of that string */
|
package/dist/index.js
CHANGED
|
@@ -1218,8 +1218,8 @@ var ManagerUtils = class {
|
|
|
1218
1218
|
* @returns
|
|
1219
1219
|
*/
|
|
1220
1220
|
isTrack(data) {
|
|
1221
|
-
if (!data) return false;
|
|
1222
|
-
if (data
|
|
1221
|
+
if (!data || typeof data !== "object") return false;
|
|
1222
|
+
if (Reflect.get(data, TrackSymbol) === true) return true;
|
|
1223
1223
|
return typeof data?.encoded === "string" && typeof data?.info === "object" && !("resolve" in data);
|
|
1224
1224
|
}
|
|
1225
1225
|
/**
|
|
@@ -1228,7 +1228,7 @@ var ManagerUtils = class {
|
|
|
1228
1228
|
*/
|
|
1229
1229
|
isUnresolvedTrack(data) {
|
|
1230
1230
|
if (!data) return false;
|
|
1231
|
-
if (data
|
|
1231
|
+
if (Reflect.get(data, UnresolvedTrackSymbol) === true) return true;
|
|
1232
1232
|
return typeof data === "object" && ("info" in data && typeof data.info.title === "string" || typeof data.encoded === "string") && "resolve" in data && typeof data.resolve === "function";
|
|
1233
1233
|
}
|
|
1234
1234
|
/**
|
|
@@ -1269,7 +1269,7 @@ var ManagerUtils = class {
|
|
|
1269
1269
|
if (node._checkForSources && !node.info.sourceManagers?.length) throw new Error("Lavalink Node, has no sourceManagers enabled");
|
|
1270
1270
|
if (!queryString.trim().length) throw new Error(`Query string is empty, please provide a valid query string.`);
|
|
1271
1271
|
if (sourceString === "speak" && queryString.length > 100) throw new Error(`Query is speak, which is limited to 100 characters.`);
|
|
1272
|
-
if (this.LavalinkManager.options?.linksBlacklist
|
|
1272
|
+
if (this.LavalinkManager?.options?.linksBlacklist && this.LavalinkManager.options?.linksBlacklist.length > 0) {
|
|
1273
1273
|
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) this.LavalinkManager.emit("debug", "ValidatingBlacklistLinks", {
|
|
1274
1274
|
state: "log",
|
|
1275
1275
|
message: `Validating Query against LavalinkManager.options.linksBlacklist, query: "${queryString}"`,
|
|
@@ -1278,9 +1278,9 @@ var ManagerUtils = class {
|
|
|
1278
1278
|
if (this.LavalinkManager.options?.linksBlacklist.some((v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString))) throw new Error(`Query string contains a link / word which is blacklisted.`);
|
|
1279
1279
|
}
|
|
1280
1280
|
if (!/^https?:\/\//.test(queryString)) return;
|
|
1281
|
-
else if (this.LavalinkManager
|
|
1282
|
-
if (this.LavalinkManager.options?.linksWhitelist
|
|
1283
|
-
if (this.LavalinkManager
|
|
1281
|
+
else if (this.LavalinkManager?.options?.linksAllowed === false) throw new Error("Using links to make a request is not allowed.");
|
|
1282
|
+
if (this.LavalinkManager?.options?.linksWhitelist && this.LavalinkManager.options?.linksWhitelist.length > 0) {
|
|
1283
|
+
if (this.LavalinkManager?.options?.advancedOptions?.enableDebugEvents) this.LavalinkManager.emit("debug", "ValidatingWhitelistLinks", {
|
|
1284
1284
|
state: "log",
|
|
1285
1285
|
message: `Link was provided to the Query, validating against LavalinkManager.options.linksWhitelist, query: "${queryString}"`,
|
|
1286
1286
|
functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()"
|
|
@@ -1404,7 +1404,7 @@ var ManagerUtils = class {
|
|
|
1404
1404
|
validateSourceString(node, sourceString) {
|
|
1405
1405
|
if (!sourceString) throw new Error(`No SourceString was provided`);
|
|
1406
1406
|
const source = this.SourcesRecord[sourceString.toLowerCase().trim()];
|
|
1407
|
-
if (!source &&
|
|
1407
|
+
if (!source && !this.LavalinkManager.options.playerOptions.allowCustomSources) throw new Error(`Lavalink-Client does not support SearchQuerySource: '${sourceString}'. You can disable this check by setting 'ManagerOptions.PlayerOptions.allowCustomSources' to true`);
|
|
1408
1408
|
if (!node.info) throw new Error("Lavalink Node does not have any info cached yet, not ready yet!");
|
|
1409
1409
|
if (!node._checkForSources) return;
|
|
1410
1410
|
if (source === "amsearch" && !node.info?.sourceManagers?.includes("applemusic")) throw new Error("Lavalink Node has not 'applemusic' enabled, which is required to have 'amsearch' work");
|
|
@@ -1965,7 +1965,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
1965
1965
|
this.sessionId = this.options.sessionId || sessionId;
|
|
1966
1966
|
}
|
|
1967
1967
|
this.socket = new WebSocket(`ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`, { headers });
|
|
1968
|
-
this.socket.on("open", this.open.
|
|
1968
|
+
this.socket.on("open", () => void this.open().catch((error) => {
|
|
1969
|
+
this.error(error);
|
|
1970
|
+
}));
|
|
1969
1971
|
this.socket.on("close", (code, reason) => void this.close(code, reason?.toString()).catch((error) => {
|
|
1970
1972
|
this.NodeManager.emit("error", this, error);
|
|
1971
1973
|
}));
|
|
@@ -2825,7 +2827,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
2825
2827
|
const player = this._LManager.getPlayer(data.guildId);
|
|
2826
2828
|
if (!player) return;
|
|
2827
2829
|
if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false) {
|
|
2828
|
-
player.destroy("LavalinkNoVoice")
|
|
2830
|
+
player.destroy("LavalinkNoVoice").catch((error) => {
|
|
2831
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
2832
|
+
});
|
|
2829
2833
|
return;
|
|
2830
2834
|
}
|
|
2831
2835
|
player.ping.ws = res?.voice?.ping || player?.ping.ws;
|
|
@@ -3124,11 +3128,12 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3124
3128
|
player.playing = true;
|
|
3125
3129
|
player.paused = false;
|
|
3126
3130
|
}
|
|
3127
|
-
if (this._LManager.options?.emitNewSongsOnly === true && player.
|
|
3131
|
+
if (this._LManager.options?.emitNewSongsOnly === true && player.getData("internal_lastEmittedTrackId") === track?.info?.identifier) return this._emitDebugEvent("TrackStartNewSongsOnly", {
|
|
3128
3132
|
state: "log",
|
|
3129
3133
|
message: `TrackStart not Emitting, because playing the previous song again.`,
|
|
3130
3134
|
functionLayer: "LavalinkNode > trackStart()"
|
|
3131
3135
|
});
|
|
3136
|
+
player.setData("internal_lastEmittedTrackId", track?.info?.identifier);
|
|
3132
3137
|
if (!player.queue.current) {
|
|
3133
3138
|
player.queue.current = this.getTrackOfPayload(payload);
|
|
3134
3139
|
if (player.queue.current) await player.queue.utils.save();
|
|
@@ -3150,6 +3155,7 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3150
3155
|
message: `TrackEnd Event does not handle any playback, because the track was replaced.`,
|
|
3151
3156
|
functionLayer: "LavalinkNode > trackEnd()"
|
|
3152
3157
|
});
|
|
3158
|
+
player.setData("internal_lastEmittedTrackId", void 0);
|
|
3153
3159
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3154
3160
|
return;
|
|
3155
3161
|
}
|
|
@@ -3159,7 +3165,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3159
3165
|
await queueTrackEnd(player);
|
|
3160
3166
|
if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
|
|
3161
3167
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3162
|
-
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true })
|
|
3168
|
+
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true }).catch((error) => {
|
|
3169
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3170
|
+
});
|
|
3163
3171
|
return;
|
|
3164
3172
|
}
|
|
3165
3173
|
if (player.repeatMode !== "track" || player.getData("internal_skipped")) await queueTrackEnd(player);
|
|
@@ -3171,7 +3179,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3171
3179
|
if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
|
|
3172
3180
|
player.setData("internal_skipped", false);
|
|
3173
3181
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3174
|
-
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true })
|
|
3182
|
+
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true }).catch((error) => {
|
|
3183
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3184
|
+
});
|
|
3175
3185
|
}
|
|
3176
3186
|
/** @private util function for handling trackStuck event */
|
|
3177
3187
|
async trackStuck(player, track, payload) {
|
|
@@ -3184,7 +3194,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3184
3194
|
message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
3185
3195
|
functionLayer: "LavalinkNode > trackStuck()"
|
|
3186
3196
|
});
|
|
3187
|
-
player.destroy("TrackStuckMaxTracksErroredPerTime")
|
|
3197
|
+
player.destroy("TrackStuckMaxTracksErroredPerTime").catch((error) => {
|
|
3198
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3199
|
+
});
|
|
3188
3200
|
return;
|
|
3189
3201
|
}
|
|
3190
3202
|
}
|
|
@@ -3203,6 +3215,8 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3203
3215
|
if (this._LManager.options.autoSkip && player.queue.current) player.play({
|
|
3204
3216
|
track: player.queue.current,
|
|
3205
3217
|
noReplace: false
|
|
3218
|
+
}).catch((error) => {
|
|
3219
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3206
3220
|
});
|
|
3207
3221
|
}
|
|
3208
3222
|
/** @private util function for handling trackError event */
|
|
@@ -3216,7 +3230,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3216
3230
|
message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
3217
3231
|
functionLayer: "LavalinkNode > trackError()"
|
|
3218
3232
|
});
|
|
3219
|
-
player.destroy("TrackErrorMaxTracksErroredPerTime")
|
|
3233
|
+
player.destroy("TrackErrorMaxTracksErroredPerTime").catch((error) => {
|
|
3234
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3235
|
+
});
|
|
3220
3236
|
return;
|
|
3221
3237
|
}
|
|
3222
3238
|
}
|
|
@@ -3316,6 +3332,7 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3316
3332
|
player.queue.current = null;
|
|
3317
3333
|
player.playing = false;
|
|
3318
3334
|
player.setData("internal_stopPlaying", void 0);
|
|
3335
|
+
player.setData("internal_lastEmittedTrackId", void 0);
|
|
3319
3336
|
this._emitDebugEvent("QueueEnded", {
|
|
3320
3337
|
state: "log",
|
|
3321
3338
|
message: `Queue Ended because no more Tracks were in the Queue, due to EventName: "${payload.type}"`,
|
|
@@ -3344,6 +3361,8 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3344
3361
|
if (this._LManager.options.autoSkip) return player.play({
|
|
3345
3362
|
noReplace: true,
|
|
3346
3363
|
paused: false
|
|
3364
|
+
}).catch((error) => {
|
|
3365
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3347
3366
|
});
|
|
3348
3367
|
} else this._emitDebugEvent("AutoplayThresholdSpamLimiter", {
|
|
3349
3368
|
state: "warn",
|
|
@@ -3361,7 +3380,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3361
3380
|
if (payload?.reason !== "stopped") await player.queue.utils.save();
|
|
3362
3381
|
if (typeof this._LManager.options.playerOptions?.onEmptyQueue?.destroyAfterMs === "number" && !isNaN(this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs) && this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs >= 0) {
|
|
3363
3382
|
if (this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) {
|
|
3364
|
-
player.destroy("QueueEmpty")
|
|
3383
|
+
player.destroy("QueueEmpty").catch((error) => {
|
|
3384
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3385
|
+
});
|
|
3365
3386
|
return;
|
|
3366
3387
|
} else {
|
|
3367
3388
|
this._emitDebugEvent("TriggerQueueEmptyInterval", {
|
|
@@ -3375,7 +3396,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3375
3396
|
player.setData("internal_queueempty", void 0);
|
|
3376
3397
|
if (player.queue.current) return this._LManager.emit("playerQueueEmptyCancel", player);
|
|
3377
3398
|
this._LManager.emit("playerQueueEmptyEnd", player);
|
|
3378
|
-
player.destroy("QueueEmpty")
|
|
3399
|
+
player.destroy("QueueEmpty").catch((error) => {
|
|
3400
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3401
|
+
});
|
|
3379
3402
|
}, this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
|
|
3380
3403
|
}
|
|
3381
3404
|
}
|
|
@@ -4989,6 +5012,14 @@ var FilterManager = class {
|
|
|
4989
5012
|
|
|
4990
5013
|
//#endregion
|
|
4991
5014
|
//#region src/structures/Queue.ts
|
|
5015
|
+
function tracksMatch(a, b) {
|
|
5016
|
+
if (a === b) return true;
|
|
5017
|
+
if (a.encoded) return a.encoded === b.encoded;
|
|
5018
|
+
if (a.info?.identifier) return a.info.identifier === b.info?.identifier;
|
|
5019
|
+
if (a.info?.uri) return a.info.uri === b.info?.uri;
|
|
5020
|
+
if (a.info?.isrc) return a.info.isrc === b.info?.isrc;
|
|
5021
|
+
return a.info?.title && a.info.title === b.info?.title || a.info?.artworkUrl && a.info.artworkUrl === b.info?.artworkUrl || false;
|
|
5022
|
+
}
|
|
4992
5023
|
var QueueSaver = class {
|
|
4993
5024
|
/**
|
|
4994
5025
|
* The queue store manager
|
|
@@ -5119,14 +5150,14 @@ var Queue = class {
|
|
|
5119
5150
|
*/
|
|
5120
5151
|
save: async () => {
|
|
5121
5152
|
if (this.previous.length > this.options.maxPreviousTracks) this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
5122
|
-
return await this.QueueSaver
|
|
5153
|
+
return await this.QueueSaver?.set(this.guildId, this.utils.toJSON());
|
|
5123
5154
|
},
|
|
5124
5155
|
/**
|
|
5125
5156
|
* Sync the current queue database/server with the cached one
|
|
5126
5157
|
* @returns {void}
|
|
5127
5158
|
*/
|
|
5128
5159
|
sync: async (override = true, dontSyncCurrent = true) => {
|
|
5129
|
-
const data = await this.QueueSaver
|
|
5160
|
+
const data = await this.QueueSaver?.get(this.guildId);
|
|
5130
5161
|
if (!data) throw new Error(`No data found to sync for guildId: ${this.guildId}`);
|
|
5131
5162
|
if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current)) this.current = data.current;
|
|
5132
5163
|
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track))) this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
@@ -5134,7 +5165,7 @@ var Queue = class {
|
|
|
5134
5165
|
await this.utils.save();
|
|
5135
5166
|
},
|
|
5136
5167
|
destroy: async () => {
|
|
5137
|
-
return await this.QueueSaver
|
|
5168
|
+
return await this.QueueSaver?.delete(this.guildId);
|
|
5138
5169
|
},
|
|
5139
5170
|
/**
|
|
5140
5171
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
|
|
@@ -5263,12 +5294,12 @@ var Queue = class {
|
|
|
5263
5294
|
* @param {number} index Where to remove the Track
|
|
5264
5295
|
* @param {number} amount How many Tracks to remove?
|
|
5265
5296
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
5266
|
-
* @returns {Track} Spliced Track
|
|
5297
|
+
* @returns {Track} Spliced (aka Removed) Track
|
|
5267
5298
|
*/
|
|
5268
5299
|
async splice(index, amount, TrackOrTracks) {
|
|
5269
5300
|
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
|
|
5270
5301
|
if (!this.tracks.length) {
|
|
5271
|
-
if (TrackOrTracks)
|
|
5302
|
+
if (TrackOrTracks) await this.add(TrackOrTracks);
|
|
5272
5303
|
return null;
|
|
5273
5304
|
}
|
|
5274
5305
|
if (TrackOrTracks && typeof this.queueChanges?.tracksAdd === "function") try {
|
|
@@ -5340,7 +5371,7 @@ var Queue = class {
|
|
|
5340
5371
|
const tracksToRemove = this.tracks.map((v, i) => ({
|
|
5341
5372
|
v,
|
|
5342
5373
|
i
|
|
5343
|
-
})).filter(({ v, i }) => removeQueryTrack.find((t) => typeof t === "number" && t === i || typeof t === "object" &&
|
|
5374
|
+
})).filter(({ v, i }) => removeQueryTrack.find((t) => typeof t === "number" && t === i || typeof t === "object" && t !== null && tracksMatch(t, v)));
|
|
5344
5375
|
if (!tracksToRemove.length) return null;
|
|
5345
5376
|
const removed = [];
|
|
5346
5377
|
tracksToRemove.sort((a, b) => b.i - a.i);
|
|
@@ -5351,7 +5382,7 @@ var Queue = class {
|
|
|
5351
5382
|
await this.utils.save();
|
|
5352
5383
|
return { removed };
|
|
5353
5384
|
}
|
|
5354
|
-
const toRemove = this.tracks.findIndex((v) => removeQueryTrack
|
|
5385
|
+
const toRemove = this.tracks.findIndex((v) => tracksMatch(removeQueryTrack, v));
|
|
5355
5386
|
if (toRemove < 0) return null;
|
|
5356
5387
|
const removed = this.tracks.splice(toRemove, 1);
|
|
5357
5388
|
if (typeof this.queueChanges?.tracksRemoved === "function") try {
|
|
@@ -5722,7 +5753,9 @@ var Player = class {
|
|
|
5722
5753
|
}
|
|
5723
5754
|
if (options?.track?.encoded || options?.track?.identifier) {
|
|
5724
5755
|
this.queue.current = options.clientTrack || null;
|
|
5725
|
-
this.queue.utils.save()
|
|
5756
|
+
this.queue.utils.save().catch((error) => {
|
|
5757
|
+
if (!this.LavalinkManager.options.catchLifeCycleRejections) throw error;
|
|
5758
|
+
});
|
|
5726
5759
|
if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
|
|
5727
5760
|
this.volume = Math.max(Math.min(options?.volume, 1e3), 0);
|
|
5728
5761
|
let vol = Number(this.volume);
|
|
@@ -5991,7 +6024,12 @@ var Player = class {
|
|
|
5991
6024
|
if (skipTo > this.queue.tracks.length) throw new RangeError("Can't skip more than the queue size");
|
|
5992
6025
|
await this.queue.splice(0, skipTo - 1);
|
|
5993
6026
|
}
|
|
5994
|
-
if (!this.playing && !this.queue.current)
|
|
6027
|
+
if (!this.playing && !this.queue.current) {
|
|
6028
|
+
this.play().catch((error) => {
|
|
6029
|
+
if (!this.LavalinkManager.options.catchLifeCycleRejections) throw error;
|
|
6030
|
+
});
|
|
6031
|
+
return this;
|
|
6032
|
+
}
|
|
5995
6033
|
const now = performance.now();
|
|
5996
6034
|
this.setData("internal_skipped", true);
|
|
5997
6035
|
await this.node.updatePlayer({
|
|
@@ -6202,6 +6240,7 @@ var Player = class {
|
|
|
6202
6240
|
const currentTrack = this.queue.current;
|
|
6203
6241
|
if (!this.voice.endpoint || !this.voice.sessionId || !this.voice.token) throw new Error("Voice Data is missing, can't change the node");
|
|
6204
6242
|
this.setData("internal_nodeChanging", true);
|
|
6243
|
+
this.setData("internal_lastEmittedTrackId", void 0);
|
|
6205
6244
|
if (this.node.connected) await this.node.destroyPlayer(this.guildId);
|
|
6206
6245
|
this.node = updateNode;
|
|
6207
6246
|
const now = performance.now();
|
|
@@ -6417,6 +6456,7 @@ var LavalinkManager = class LavalinkManager extends EventEmitter {
|
|
|
6417
6456
|
linksAllowed: options?.linksAllowed ?? true,
|
|
6418
6457
|
autoSkip: options?.autoSkip ?? true,
|
|
6419
6458
|
autoSkipOnResolveError: options?.autoSkipOnResolveError ?? true,
|
|
6459
|
+
catchLifeCycleRejections: options?.catchLifeCycleRejections ?? false,
|
|
6420
6460
|
emitNewSongsOnly: options?.emitNewSongsOnly ?? false,
|
|
6421
6461
|
queueOptions: {
|
|
6422
6462
|
maxPreviousTracks: options?.queueOptions?.maxPreviousTracks ?? 25,
|
|
@@ -6452,6 +6492,7 @@ var LavalinkManager = class LavalinkManager extends EventEmitter {
|
|
|
6452
6492
|
if (typeof options?.sendToShard !== "function") throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
|
|
6453
6493
|
if (options?.autoSkip && typeof options?.autoSkip !== "boolean") throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
|
|
6454
6494
|
if (options?.autoSkipOnResolveError && typeof options?.autoSkipOnResolveError !== "boolean") throw new SyntaxError("ManagerOption.autoSkipOnResolveError must be either false | true aka boolean");
|
|
6495
|
+
if (options?.catchLifeCycleRejections && typeof options?.catchLifeCycleRejections !== "boolean") throw new SyntaxError("ManagerOption.catchLifeCycleRejections must be either false | true aka boolean");
|
|
6455
6496
|
if (options?.emitNewSongsOnly && typeof options?.emitNewSongsOnly !== "boolean") throw new SyntaxError("ManagerOption.emitNewSongsOnly must be either false | true aka boolean");
|
|
6456
6497
|
if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every((node) => node instanceof NodeLinkNode || node instanceof LavalinkNode || this.utils.isNodeOptions(node))) throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions or the Node-Classes 'NodeLinkNode' or 'LavalinkNode' and is required of at least 1 Node");
|
|
6457
6498
|
if (options?.queueOptions?.queueStore) {
|
|
@@ -6759,7 +6800,9 @@ var LavalinkManager = class LavalinkManager extends EventEmitter {
|
|
|
6759
6800
|
const update = "d" in data ? data.d : data;
|
|
6760
6801
|
if (!update.guild_id) return;
|
|
6761
6802
|
const player = this.getPlayer(update.guild_id);
|
|
6762
|
-
if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted")
|
|
6803
|
+
if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted").catch((error) => {
|
|
6804
|
+
if (!this.options.catchLifeCycleRejections) throw error;
|
|
6805
|
+
});
|
|
6763
6806
|
}
|
|
6764
6807
|
if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
|
|
6765
6808
|
const update = "d" in data ? data.d : data;
|
package/dist/index.mjs
CHANGED
|
@@ -1218,8 +1218,8 @@ var ManagerUtils = class {
|
|
|
1218
1218
|
* @returns
|
|
1219
1219
|
*/
|
|
1220
1220
|
isTrack(data) {
|
|
1221
|
-
if (!data) return false;
|
|
1222
|
-
if (data
|
|
1221
|
+
if (!data || typeof data !== "object") return false;
|
|
1222
|
+
if (Reflect.get(data, TrackSymbol) === true) return true;
|
|
1223
1223
|
return typeof data?.encoded === "string" && typeof data?.info === "object" && !("resolve" in data);
|
|
1224
1224
|
}
|
|
1225
1225
|
/**
|
|
@@ -1228,7 +1228,7 @@ var ManagerUtils = class {
|
|
|
1228
1228
|
*/
|
|
1229
1229
|
isUnresolvedTrack(data) {
|
|
1230
1230
|
if (!data) return false;
|
|
1231
|
-
if (data
|
|
1231
|
+
if (Reflect.get(data, UnresolvedTrackSymbol) === true) return true;
|
|
1232
1232
|
return typeof data === "object" && ("info" in data && typeof data.info.title === "string" || typeof data.encoded === "string") && "resolve" in data && typeof data.resolve === "function";
|
|
1233
1233
|
}
|
|
1234
1234
|
/**
|
|
@@ -1269,7 +1269,7 @@ var ManagerUtils = class {
|
|
|
1269
1269
|
if (node._checkForSources && !node.info.sourceManagers?.length) throw new Error("Lavalink Node, has no sourceManagers enabled");
|
|
1270
1270
|
if (!queryString.trim().length) throw new Error(`Query string is empty, please provide a valid query string.`);
|
|
1271
1271
|
if (sourceString === "speak" && queryString.length > 100) throw new Error(`Query is speak, which is limited to 100 characters.`);
|
|
1272
|
-
if (this.LavalinkManager.options?.linksBlacklist
|
|
1272
|
+
if (this.LavalinkManager?.options?.linksBlacklist && this.LavalinkManager.options?.linksBlacklist.length > 0) {
|
|
1273
1273
|
if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) this.LavalinkManager.emit("debug", "ValidatingBlacklistLinks", {
|
|
1274
1274
|
state: "log",
|
|
1275
1275
|
message: `Validating Query against LavalinkManager.options.linksBlacklist, query: "${queryString}"`,
|
|
@@ -1278,9 +1278,9 @@ var ManagerUtils = class {
|
|
|
1278
1278
|
if (this.LavalinkManager.options?.linksBlacklist.some((v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString))) throw new Error(`Query string contains a link / word which is blacklisted.`);
|
|
1279
1279
|
}
|
|
1280
1280
|
if (!/^https?:\/\//.test(queryString)) return;
|
|
1281
|
-
else if (this.LavalinkManager
|
|
1282
|
-
if (this.LavalinkManager.options?.linksWhitelist
|
|
1283
|
-
if (this.LavalinkManager
|
|
1281
|
+
else if (this.LavalinkManager?.options?.linksAllowed === false) throw new Error("Using links to make a request is not allowed.");
|
|
1282
|
+
if (this.LavalinkManager?.options?.linksWhitelist && this.LavalinkManager.options?.linksWhitelist.length > 0) {
|
|
1283
|
+
if (this.LavalinkManager?.options?.advancedOptions?.enableDebugEvents) this.LavalinkManager.emit("debug", "ValidatingWhitelistLinks", {
|
|
1284
1284
|
state: "log",
|
|
1285
1285
|
message: `Link was provided to the Query, validating against LavalinkManager.options.linksWhitelist, query: "${queryString}"`,
|
|
1286
1286
|
functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()"
|
|
@@ -1404,7 +1404,7 @@ var ManagerUtils = class {
|
|
|
1404
1404
|
validateSourceString(node, sourceString) {
|
|
1405
1405
|
if (!sourceString) throw new Error(`No SourceString was provided`);
|
|
1406
1406
|
const source = this.SourcesRecord[sourceString.toLowerCase().trim()];
|
|
1407
|
-
if (!source &&
|
|
1407
|
+
if (!source && !this.LavalinkManager.options.playerOptions.allowCustomSources) throw new Error(`Lavalink-Client does not support SearchQuerySource: '${sourceString}'. You can disable this check by setting 'ManagerOptions.PlayerOptions.allowCustomSources' to true`);
|
|
1408
1408
|
if (!node.info) throw new Error("Lavalink Node does not have any info cached yet, not ready yet!");
|
|
1409
1409
|
if (!node._checkForSources) return;
|
|
1410
1410
|
if (source === "amsearch" && !node.info?.sourceManagers?.includes("applemusic")) throw new Error("Lavalink Node has not 'applemusic' enabled, which is required to have 'amsearch' work");
|
|
@@ -1965,7 +1965,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
1965
1965
|
this.sessionId = this.options.sessionId || sessionId;
|
|
1966
1966
|
}
|
|
1967
1967
|
this.socket = new WebSocket(`ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`, { headers });
|
|
1968
|
-
this.socket.on("open", this.open.
|
|
1968
|
+
this.socket.on("open", () => void this.open().catch((error) => {
|
|
1969
|
+
this.error(error);
|
|
1970
|
+
}));
|
|
1969
1971
|
this.socket.on("close", (code, reason) => void this.close(code, reason?.toString()).catch((error) => {
|
|
1970
1972
|
this.NodeManager.emit("error", this, error);
|
|
1971
1973
|
}));
|
|
@@ -2825,7 +2827,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
2825
2827
|
const player = this._LManager.getPlayer(data.guildId);
|
|
2826
2828
|
if (!player) return;
|
|
2827
2829
|
if (typeof res?.voice?.connected === "boolean" && res.voice.connected === false) {
|
|
2828
|
-
player.destroy("LavalinkNoVoice")
|
|
2830
|
+
player.destroy("LavalinkNoVoice").catch((error) => {
|
|
2831
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
2832
|
+
});
|
|
2829
2833
|
return;
|
|
2830
2834
|
}
|
|
2831
2835
|
player.ping.ws = res?.voice?.ping || player?.ping.ws;
|
|
@@ -3124,11 +3128,12 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3124
3128
|
player.playing = true;
|
|
3125
3129
|
player.paused = false;
|
|
3126
3130
|
}
|
|
3127
|
-
if (this._LManager.options?.emitNewSongsOnly === true && player.
|
|
3131
|
+
if (this._LManager.options?.emitNewSongsOnly === true && player.getData("internal_lastEmittedTrackId") === track?.info?.identifier) return this._emitDebugEvent("TrackStartNewSongsOnly", {
|
|
3128
3132
|
state: "log",
|
|
3129
3133
|
message: `TrackStart not Emitting, because playing the previous song again.`,
|
|
3130
3134
|
functionLayer: "LavalinkNode > trackStart()"
|
|
3131
3135
|
});
|
|
3136
|
+
player.setData("internal_lastEmittedTrackId", track?.info?.identifier);
|
|
3132
3137
|
if (!player.queue.current) {
|
|
3133
3138
|
player.queue.current = this.getTrackOfPayload(payload);
|
|
3134
3139
|
if (player.queue.current) await player.queue.utils.save();
|
|
@@ -3150,6 +3155,7 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3150
3155
|
message: `TrackEnd Event does not handle any playback, because the track was replaced.`,
|
|
3151
3156
|
functionLayer: "LavalinkNode > trackEnd()"
|
|
3152
3157
|
});
|
|
3158
|
+
player.setData("internal_lastEmittedTrackId", void 0);
|
|
3153
3159
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3154
3160
|
return;
|
|
3155
3161
|
}
|
|
@@ -3159,7 +3165,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3159
3165
|
await queueTrackEnd(player);
|
|
3160
3166
|
if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
|
|
3161
3167
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3162
|
-
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true })
|
|
3168
|
+
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true }).catch((error) => {
|
|
3169
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3170
|
+
});
|
|
3163
3171
|
return;
|
|
3164
3172
|
}
|
|
3165
3173
|
if (player.repeatMode !== "track" || player.getData("internal_skipped")) await queueTrackEnd(player);
|
|
@@ -3171,7 +3179,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3171
3179
|
if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
|
|
3172
3180
|
player.setData("internal_skipped", false);
|
|
3173
3181
|
this._LManager.emit("trackEnd", player, trackToUse, payload);
|
|
3174
|
-
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true })
|
|
3182
|
+
if (this._LManager.options.autoSkip && player.queue.current) player.play({ noReplace: true }).catch((error) => {
|
|
3183
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3184
|
+
});
|
|
3175
3185
|
}
|
|
3176
3186
|
/** @private util function for handling trackStuck event */
|
|
3177
3187
|
async trackStuck(player, track, payload) {
|
|
@@ -3184,7 +3194,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3184
3194
|
message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
3185
3195
|
functionLayer: "LavalinkNode > trackStuck()"
|
|
3186
3196
|
});
|
|
3187
|
-
player.destroy("TrackStuckMaxTracksErroredPerTime")
|
|
3197
|
+
player.destroy("TrackStuckMaxTracksErroredPerTime").catch((error) => {
|
|
3198
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3199
|
+
});
|
|
3188
3200
|
return;
|
|
3189
3201
|
}
|
|
3190
3202
|
}
|
|
@@ -3203,6 +3215,8 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3203
3215
|
if (this._LManager.options.autoSkip && player.queue.current) player.play({
|
|
3204
3216
|
track: player.queue.current,
|
|
3205
3217
|
noReplace: false
|
|
3218
|
+
}).catch((error) => {
|
|
3219
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3206
3220
|
});
|
|
3207
3221
|
}
|
|
3208
3222
|
/** @private util function for handling trackError event */
|
|
@@ -3216,7 +3230,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3216
3230
|
message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
|
|
3217
3231
|
functionLayer: "LavalinkNode > trackError()"
|
|
3218
3232
|
});
|
|
3219
|
-
player.destroy("TrackErrorMaxTracksErroredPerTime")
|
|
3233
|
+
player.destroy("TrackErrorMaxTracksErroredPerTime").catch((error) => {
|
|
3234
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3235
|
+
});
|
|
3220
3236
|
return;
|
|
3221
3237
|
}
|
|
3222
3238
|
}
|
|
@@ -3316,6 +3332,7 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3316
3332
|
player.queue.current = null;
|
|
3317
3333
|
player.playing = false;
|
|
3318
3334
|
player.setData("internal_stopPlaying", void 0);
|
|
3335
|
+
player.setData("internal_lastEmittedTrackId", void 0);
|
|
3319
3336
|
this._emitDebugEvent("QueueEnded", {
|
|
3320
3337
|
state: "log",
|
|
3321
3338
|
message: `Queue Ended because no more Tracks were in the Queue, due to EventName: "${payload.type}"`,
|
|
@@ -3344,6 +3361,8 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3344
3361
|
if (this._LManager.options.autoSkip) return player.play({
|
|
3345
3362
|
noReplace: true,
|
|
3346
3363
|
paused: false
|
|
3364
|
+
}).catch((error) => {
|
|
3365
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3347
3366
|
});
|
|
3348
3367
|
} else this._emitDebugEvent("AutoplayThresholdSpamLimiter", {
|
|
3349
3368
|
state: "warn",
|
|
@@ -3361,7 +3380,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3361
3380
|
if (payload?.reason !== "stopped") await player.queue.utils.save();
|
|
3362
3381
|
if (typeof this._LManager.options.playerOptions?.onEmptyQueue?.destroyAfterMs === "number" && !isNaN(this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs) && this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs >= 0) {
|
|
3363
3382
|
if (this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) {
|
|
3364
|
-
player.destroy("QueueEmpty")
|
|
3383
|
+
player.destroy("QueueEmpty").catch((error) => {
|
|
3384
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3385
|
+
});
|
|
3365
3386
|
return;
|
|
3366
3387
|
} else {
|
|
3367
3388
|
this._emitDebugEvent("TriggerQueueEmptyInterval", {
|
|
@@ -3375,7 +3396,9 @@ var LavalinkNode = class LavalinkNode {
|
|
|
3375
3396
|
player.setData("internal_queueempty", void 0);
|
|
3376
3397
|
if (player.queue.current) return this._LManager.emit("playerQueueEmptyCancel", player);
|
|
3377
3398
|
this._LManager.emit("playerQueueEmptyEnd", player);
|
|
3378
|
-
player.destroy("QueueEmpty")
|
|
3399
|
+
player.destroy("QueueEmpty").catch((error) => {
|
|
3400
|
+
if (!this._LManager.options.catchLifeCycleRejections) throw error;
|
|
3401
|
+
});
|
|
3379
3402
|
}, this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
|
|
3380
3403
|
}
|
|
3381
3404
|
}
|
|
@@ -4989,6 +5012,14 @@ var FilterManager = class {
|
|
|
4989
5012
|
|
|
4990
5013
|
//#endregion
|
|
4991
5014
|
//#region src/structures/Queue.ts
|
|
5015
|
+
function tracksMatch(a, b) {
|
|
5016
|
+
if (a === b) return true;
|
|
5017
|
+
if (a.encoded) return a.encoded === b.encoded;
|
|
5018
|
+
if (a.info?.identifier) return a.info.identifier === b.info?.identifier;
|
|
5019
|
+
if (a.info?.uri) return a.info.uri === b.info?.uri;
|
|
5020
|
+
if (a.info?.isrc) return a.info.isrc === b.info?.isrc;
|
|
5021
|
+
return a.info?.title && a.info.title === b.info?.title || a.info?.artworkUrl && a.info.artworkUrl === b.info?.artworkUrl || false;
|
|
5022
|
+
}
|
|
4992
5023
|
var QueueSaver = class {
|
|
4993
5024
|
/**
|
|
4994
5025
|
* The queue store manager
|
|
@@ -5119,14 +5150,14 @@ var Queue = class {
|
|
|
5119
5150
|
*/
|
|
5120
5151
|
save: async () => {
|
|
5121
5152
|
if (this.previous.length > this.options.maxPreviousTracks) this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
|
|
5122
|
-
return await this.QueueSaver
|
|
5153
|
+
return await this.QueueSaver?.set(this.guildId, this.utils.toJSON());
|
|
5123
5154
|
},
|
|
5124
5155
|
/**
|
|
5125
5156
|
* Sync the current queue database/server with the cached one
|
|
5126
5157
|
* @returns {void}
|
|
5127
5158
|
*/
|
|
5128
5159
|
sync: async (override = true, dontSyncCurrent = true) => {
|
|
5129
|
-
const data = await this.QueueSaver
|
|
5160
|
+
const data = await this.QueueSaver?.get(this.guildId);
|
|
5130
5161
|
if (!data) throw new Error(`No data found to sync for guildId: ${this.guildId}`);
|
|
5131
5162
|
if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current)) this.current = data.current;
|
|
5132
5163
|
if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track))) this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
|
|
@@ -5134,7 +5165,7 @@ var Queue = class {
|
|
|
5134
5165
|
await this.utils.save();
|
|
5135
5166
|
},
|
|
5136
5167
|
destroy: async () => {
|
|
5137
|
-
return await this.QueueSaver
|
|
5168
|
+
return await this.QueueSaver?.delete(this.guildId);
|
|
5138
5169
|
},
|
|
5139
5170
|
/**
|
|
5140
5171
|
* @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
|
|
@@ -5263,12 +5294,12 @@ var Queue = class {
|
|
|
5263
5294
|
* @param {number} index Where to remove the Track
|
|
5264
5295
|
* @param {number} amount How many Tracks to remove?
|
|
5265
5296
|
* @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
|
|
5266
|
-
* @returns {Track} Spliced Track
|
|
5297
|
+
* @returns {Track} Spliced (aka Removed) Track
|
|
5267
5298
|
*/
|
|
5268
5299
|
async splice(index, amount, TrackOrTracks) {
|
|
5269
5300
|
const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
|
|
5270
5301
|
if (!this.tracks.length) {
|
|
5271
|
-
if (TrackOrTracks)
|
|
5302
|
+
if (TrackOrTracks) await this.add(TrackOrTracks);
|
|
5272
5303
|
return null;
|
|
5273
5304
|
}
|
|
5274
5305
|
if (TrackOrTracks && typeof this.queueChanges?.tracksAdd === "function") try {
|
|
@@ -5340,7 +5371,7 @@ var Queue = class {
|
|
|
5340
5371
|
const tracksToRemove = this.tracks.map((v, i) => ({
|
|
5341
5372
|
v,
|
|
5342
5373
|
i
|
|
5343
|
-
})).filter(({ v, i }) => removeQueryTrack.find((t) => typeof t === "number" && t === i || typeof t === "object" &&
|
|
5374
|
+
})).filter(({ v, i }) => removeQueryTrack.find((t) => typeof t === "number" && t === i || typeof t === "object" && t !== null && tracksMatch(t, v)));
|
|
5344
5375
|
if (!tracksToRemove.length) return null;
|
|
5345
5376
|
const removed = [];
|
|
5346
5377
|
tracksToRemove.sort((a, b) => b.i - a.i);
|
|
@@ -5351,7 +5382,7 @@ var Queue = class {
|
|
|
5351
5382
|
await this.utils.save();
|
|
5352
5383
|
return { removed };
|
|
5353
5384
|
}
|
|
5354
|
-
const toRemove = this.tracks.findIndex((v) => removeQueryTrack
|
|
5385
|
+
const toRemove = this.tracks.findIndex((v) => tracksMatch(removeQueryTrack, v));
|
|
5355
5386
|
if (toRemove < 0) return null;
|
|
5356
5387
|
const removed = this.tracks.splice(toRemove, 1);
|
|
5357
5388
|
if (typeof this.queueChanges?.tracksRemoved === "function") try {
|
|
@@ -5722,7 +5753,9 @@ var Player = class {
|
|
|
5722
5753
|
}
|
|
5723
5754
|
if (options?.track?.encoded || options?.track?.identifier) {
|
|
5724
5755
|
this.queue.current = options.clientTrack || null;
|
|
5725
|
-
this.queue.utils.save()
|
|
5756
|
+
this.queue.utils.save().catch((error) => {
|
|
5757
|
+
if (!this.LavalinkManager.options.catchLifeCycleRejections) throw error;
|
|
5758
|
+
});
|
|
5726
5759
|
if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
|
|
5727
5760
|
this.volume = Math.max(Math.min(options?.volume, 1e3), 0);
|
|
5728
5761
|
let vol = Number(this.volume);
|
|
@@ -5991,7 +6024,12 @@ var Player = class {
|
|
|
5991
6024
|
if (skipTo > this.queue.tracks.length) throw new RangeError("Can't skip more than the queue size");
|
|
5992
6025
|
await this.queue.splice(0, skipTo - 1);
|
|
5993
6026
|
}
|
|
5994
|
-
if (!this.playing && !this.queue.current)
|
|
6027
|
+
if (!this.playing && !this.queue.current) {
|
|
6028
|
+
this.play().catch((error) => {
|
|
6029
|
+
if (!this.LavalinkManager.options.catchLifeCycleRejections) throw error;
|
|
6030
|
+
});
|
|
6031
|
+
return this;
|
|
6032
|
+
}
|
|
5995
6033
|
const now = performance.now();
|
|
5996
6034
|
this.setData("internal_skipped", true);
|
|
5997
6035
|
await this.node.updatePlayer({
|
|
@@ -6202,6 +6240,7 @@ var Player = class {
|
|
|
6202
6240
|
const currentTrack = this.queue.current;
|
|
6203
6241
|
if (!this.voice.endpoint || !this.voice.sessionId || !this.voice.token) throw new Error("Voice Data is missing, can't change the node");
|
|
6204
6242
|
this.setData("internal_nodeChanging", true);
|
|
6243
|
+
this.setData("internal_lastEmittedTrackId", void 0);
|
|
6205
6244
|
if (this.node.connected) await this.node.destroyPlayer(this.guildId);
|
|
6206
6245
|
this.node = updateNode;
|
|
6207
6246
|
const now = performance.now();
|
|
@@ -6417,6 +6456,7 @@ var LavalinkManager = class LavalinkManager extends EventEmitter {
|
|
|
6417
6456
|
linksAllowed: options?.linksAllowed ?? true,
|
|
6418
6457
|
autoSkip: options?.autoSkip ?? true,
|
|
6419
6458
|
autoSkipOnResolveError: options?.autoSkipOnResolveError ?? true,
|
|
6459
|
+
catchLifeCycleRejections: options?.catchLifeCycleRejections ?? false,
|
|
6420
6460
|
emitNewSongsOnly: options?.emitNewSongsOnly ?? false,
|
|
6421
6461
|
queueOptions: {
|
|
6422
6462
|
maxPreviousTracks: options?.queueOptions?.maxPreviousTracks ?? 25,
|
|
@@ -6452,6 +6492,7 @@ var LavalinkManager = class LavalinkManager extends EventEmitter {
|
|
|
6452
6492
|
if (typeof options?.sendToShard !== "function") throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
|
|
6453
6493
|
if (options?.autoSkip && typeof options?.autoSkip !== "boolean") throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
|
|
6454
6494
|
if (options?.autoSkipOnResolveError && typeof options?.autoSkipOnResolveError !== "boolean") throw new SyntaxError("ManagerOption.autoSkipOnResolveError must be either false | true aka boolean");
|
|
6495
|
+
if (options?.catchLifeCycleRejections && typeof options?.catchLifeCycleRejections !== "boolean") throw new SyntaxError("ManagerOption.catchLifeCycleRejections must be either false | true aka boolean");
|
|
6455
6496
|
if (options?.emitNewSongsOnly && typeof options?.emitNewSongsOnly !== "boolean") throw new SyntaxError("ManagerOption.emitNewSongsOnly must be either false | true aka boolean");
|
|
6456
6497
|
if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every((node) => node instanceof NodeLinkNode || node instanceof LavalinkNode || this.utils.isNodeOptions(node))) throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions or the Node-Classes 'NodeLinkNode' or 'LavalinkNode' and is required of at least 1 Node");
|
|
6457
6498
|
if (options?.queueOptions?.queueStore) {
|
|
@@ -6759,7 +6800,9 @@ var LavalinkManager = class LavalinkManager extends EventEmitter {
|
|
|
6759
6800
|
const update = "d" in data ? data.d : data;
|
|
6760
6801
|
if (!update.guild_id) return;
|
|
6761
6802
|
const player = this.getPlayer(update.guild_id);
|
|
6762
|
-
if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted")
|
|
6803
|
+
if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted").catch((error) => {
|
|
6804
|
+
if (!this.options.catchLifeCycleRejections) throw error;
|
|
6805
|
+
});
|
|
6763
6806
|
}
|
|
6764
6807
|
if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
|
|
6765
6808
|
const update = "d" in data ? data.d : data;
|
package/package.json
CHANGED