lavalink-client 2.9.10 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -45,6 +45,7 @@ __export(index_exports, {
45
45
  NodeLinkNode: () => NodeLinkNode,
46
46
  NodeManager: () => NodeManager,
47
47
  NodeSymbol: () => NodeSymbol,
48
+ NodeType: () => NodeType,
48
49
  Player: () => Player,
49
50
  Queue: () => Queue,
50
51
  QueueSaver: () => QueueSaver,
@@ -403,9 +404,6 @@ var NodeLinkExclusiveEvents = [
403
404
  "LyricsNotFoundEvent"
404
405
  ];
405
406
 
406
- // src/structures/NodeManager.ts
407
- var import_node_events = require("events");
408
-
409
407
  // src/structures/Node.ts
410
408
  var import_node_path = require("path");
411
409
  var import_ws = __toESM(require("ws"), 1);
@@ -418,6 +416,11 @@ var ReconnectionState = /* @__PURE__ */ ((ReconnectionState2) => {
418
416
  ReconnectionState2["DESTROYING"] = "DESTROYING";
419
417
  return ReconnectionState2;
420
418
  })(ReconnectionState || {});
419
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
420
+ NodeType2["Lavalink"] = "Lavalink";
421
+ NodeType2["NodeLink"] = "NodeLink";
422
+ return NodeType2;
423
+ })(NodeType || {});
421
424
 
422
425
  // src/structures/Utils.ts
423
426
  var import_node_url = require("url");
@@ -589,12 +592,14 @@ var QueueSymbol = /* @__PURE__ */ Symbol("LC-Queue");
589
592
  var NodeSymbol = /* @__PURE__ */ Symbol("LC-Node");
590
593
  var escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
591
594
  function parseLavalinkConnUrl(connectionUrl) {
592
- if (!connectionUrl.startsWith("lavalink://") && !connectionUrl.startsWith("nodelink://"))
595
+ if (!connectionUrl) throw new Error("ConnectionUrl is required");
596
+ const lowered = connectionUrl.toLowerCase();
597
+ if (!lowered.startsWith("lavalink://") && !lowered.startsWith("nodelink://"))
593
598
  throw new Error(`ConnectionUrl (${connectionUrl}) must start with 'lavalink://' or 'nodelink://'`);
594
599
  const parsed = new import_node_url.URL(connectionUrl);
595
600
  return {
596
601
  authorization: parsed.password,
597
- nodeType: connectionUrl.startsWith("lavalink://") ? "Lavalink" : "NodeLink",
602
+ nodeType: lowered.startsWith("lavalink://") ? "Lavalink" /* Lavalink */ : "NodeLink" /* NodeLink */,
598
603
  id: parsed.username,
599
604
  host: parsed.hostname,
600
605
  port: Number(parsed.port)
@@ -1248,7 +1253,7 @@ var LavalinkNode = class _LavalinkNode {
1248
1253
  heartBeatPongTimestamp = 0;
1249
1254
  heartBeatInterval;
1250
1255
  pingTimeout;
1251
- nodeType = "Lavalink";
1256
+ nodeType = "Lavalink" /* Lavalink */;
1252
1257
  isAlive = false;
1253
1258
  static _NodeLinkClass = null;
1254
1259
  /** The provided Options of the Node */
@@ -1322,7 +1327,7 @@ var LavalinkNode = class _LavalinkNode {
1322
1327
  * Returns wether the plugin validations are enabled or not
1323
1328
  */
1324
1329
  get _checkForPlugins() {
1325
- if (this.nodeType === "NodeLink") return false;
1330
+ if (this.nodeType === "NodeLink" /* NodeLink */) return false;
1326
1331
  return !!this.options?.autoChecks?.pluginValidations;
1327
1332
  }
1328
1333
  /**
@@ -1392,16 +1397,17 @@ var LavalinkNode = class _LavalinkNode {
1392
1397
  heartBeatInterval: 3e4,
1393
1398
  enablePingOnStatsCheck: true,
1394
1399
  closeOnError: true,
1400
+ nodeType: "Lavalink" /* Lavalink */,
1395
1401
  ...options,
1396
1402
  autoChecks: {
1397
1403
  sourcesValidations: options?.autoChecks?.sourcesValidations ?? true,
1398
1404
  pluginValidations: options?.autoChecks?.pluginValidations ?? true
1399
1405
  }
1400
1406
  };
1401
- if (this.options.nodeType === "NodeLink" && this.constructor.name === "LavalinkNode" && _LavalinkNode._NodeLinkClass) {
1407
+ if (this.options.nodeType === "NodeLink" /* NodeLink */ && this.constructor.name === "LavalinkNode" && _LavalinkNode._NodeLinkClass) {
1402
1408
  return new _LavalinkNode._NodeLinkClass(options, manager);
1403
1409
  }
1404
- this.nodeType = this.options.nodeType || "Lavalink";
1410
+ this.nodeType = this.options.nodeType;
1405
1411
  this.NodeManager = manager;
1406
1412
  this.validate();
1407
1413
  if (this.options.secure && this.options.port !== 443)
@@ -2344,20 +2350,22 @@ var LavalinkNode = class _LavalinkNode {
2344
2350
  throw new SyntaxError("LavalinkNode.autoChecks.pluginValidations must be either false | true aka boolean");
2345
2351
  if (this.options.regions !== void 0 && (!Array.isArray(this.options.regions) || !this.options.regions.every((r) => typeof r === "string")))
2346
2352
  throw new SyntaxError("LavalinkNode.regions must be an Array of strings");
2353
+ if (this.options.nodeType && !NodeType[this.options.nodeType])
2354
+ throw new SyntaxError("LavalinkNode.nodeType must be a valid NodeType enum value");
2347
2355
  }
2348
2356
  /**
2349
2357
  * Checks if the node is a NodeLink node
2350
2358
  * @returns true if the node is a NodeLink node
2351
2359
  */
2352
2360
  isNodeLink() {
2353
- return this.nodeType === "NodeLink";
2361
+ return this.nodeType === "NodeLink" /* NodeLink */;
2354
2362
  }
2355
2363
  /**
2356
2364
  * Checks if the node is a Lavalink node
2357
2365
  * @returns true if the node is a Lavalink node
2358
2366
  */
2359
2367
  isLavalinkNode() {
2360
- return this.nodeType === "Lavalink";
2368
+ return this.nodeType === "Lavalink" /* Lavalink */;
2361
2369
  }
2362
2370
  /**
2363
2371
  * Sync the data of the player you make an action to lavalink to
@@ -2743,7 +2751,7 @@ var LavalinkNode = class _LavalinkNode {
2743
2751
  }
2744
2752
  /** @private util function for handling trackStart event */
2745
2753
  async trackStart(player, track, payload) {
2746
- if (!player.get("internal_nodeChanging")) {
2754
+ if (!player.getData("internal_nodeChanging")) {
2747
2755
  player.playing = true;
2748
2756
  player.paused = false;
2749
2757
  }
@@ -2771,7 +2779,7 @@ var LavalinkNode = class _LavalinkNode {
2771
2779
  }
2772
2780
  /** @private util function for handling trackEnd event */
2773
2781
  async trackEnd(player, track, payload) {
2774
- if (player.get("internal_nodeChanging") === true) return;
2782
+ if (player.getData("internal_nodeChanging") === true) return;
2775
2783
  const trackToUse = track || this.getTrackOfPayload(payload);
2776
2784
  if (payload.reason === "replaced") {
2777
2785
  this._emitDebugEvent("TrackEndReplaced" /* TrackEndReplaced */, {
@@ -2782,10 +2790,10 @@ var LavalinkNode = class _LavalinkNode {
2782
2790
  this._LManager.emit("trackEnd", player, trackToUse, payload);
2783
2791
  return;
2784
2792
  }
2785
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
2793
+ if (!player.queue.tracks.length && (player.repeatMode === "off" || player.getData("internal_stopPlaying")))
2786
2794
  return this.queueEnd(player, track, payload);
2787
2795
  if (["loadFailed", "cleanup"].includes(payload.reason)) {
2788
- if (player.get("internal_destroystatus") === true) return;
2796
+ if (player.getData("internal_destroystatus") === true) return;
2789
2797
  await queueTrackEnd(player);
2790
2798
  if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
2791
2799
  this._LManager.emit("trackEnd", player, trackToUse, payload);
@@ -2794,7 +2802,7 @@ var LavalinkNode = class _LavalinkNode {
2794
2802
  }
2795
2803
  return;
2796
2804
  }
2797
- if (player.repeatMode !== "track" || player.get("internal_skipped")) await queueTrackEnd(player);
2805
+ if (player.repeatMode !== "track" || player.getData("internal_skipped")) await queueTrackEnd(player);
2798
2806
  else if (trackToUse && !trackToUse?.pluginInfo?.clientData?.previousTrack) {
2799
2807
  player.queue.previous.unshift(trackToUse);
2800
2808
  if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
@@ -2802,7 +2810,7 @@ var LavalinkNode = class _LavalinkNode {
2802
2810
  await player.queue.utils.save();
2803
2811
  }
2804
2812
  if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
2805
- player.set("internal_skipped", false);
2813
+ player.setData("internal_skipped", false);
2806
2814
  this._LManager.emit("trackEnd", player, trackToUse, payload);
2807
2815
  if (this._LManager.options.autoSkip && player.queue.current) {
2808
2816
  player.play({ noReplace: true });
@@ -2812,10 +2820,10 @@ var LavalinkNode = class _LavalinkNode {
2812
2820
  /** @private util function for handling trackStuck event */
2813
2821
  async trackStuck(player, track, payload) {
2814
2822
  if (this._LManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) {
2815
- const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || []).filter(
2823
+ const oldTimestamps = (player.getData("internal_erroredTracksTimestamps") || []).filter(
2816
2824
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2817
2825
  );
2818
- player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2826
+ player.setData("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2819
2827
  if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2820
2828
  this._emitDebugEvent("TrackStuckMaxTracksErroredPerTime" /* TrackStuckMaxTracksErroredPerTime */, {
2821
2829
  state: "log",
@@ -2827,7 +2835,7 @@ var LavalinkNode = class _LavalinkNode {
2827
2835
  }
2828
2836
  }
2829
2837
  this._LManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
2830
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying"))) {
2838
+ if (!player.queue.tracks.length && (player.repeatMode === "off" || player.getData("internal_stopPlaying"))) {
2831
2839
  try {
2832
2840
  await player.node.updatePlayer({
2833
2841
  guildId: player.guildId,
@@ -2850,10 +2858,10 @@ var LavalinkNode = class _LavalinkNode {
2850
2858
  /** @private util function for handling trackError event */
2851
2859
  async trackError(player, track, payload) {
2852
2860
  if (this._LManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) {
2853
- const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || []).filter(
2861
+ const oldTimestamps = (player.getData("internal_erroredTracksTimestamps") || []).filter(
2854
2862
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2855
2863
  );
2856
- player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2864
+ player.setData("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2857
2865
  if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2858
2866
  this._emitDebugEvent("TrackErrorMaxTracksErroredPerTime" /* TrackErrorMaxTracksErroredPerTime */, {
2859
2867
  state: "log",
@@ -2937,7 +2945,7 @@ var LavalinkNode = class _LavalinkNode {
2937
2945
  };
2938
2946
  r.body = safeStringify(segments.map((v) => v.toLowerCase()));
2939
2947
  });
2940
- player.set(
2948
+ player.setData(
2941
2949
  "internal_sponsorBlockCategories",
2942
2950
  segments.map((v) => v.toLowerCase())
2943
2951
  );
@@ -2965,7 +2973,7 @@ var LavalinkNode = class _LavalinkNode {
2965
2973
  await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, (r) => {
2966
2974
  r.method = "DELETE";
2967
2975
  });
2968
- player.set("internal_sponsorBlockCategories", []);
2976
+ player.setData("internal_sponsorBlockCategories", []);
2969
2977
  this._emitDebugEvent("DeleteSponsorBlock" /* DeleteSponsorBlock */, {
2970
2978
  state: "log",
2971
2979
  message: `SponsorBlock was deleted for Player: ${player.guildId}`,
@@ -2975,26 +2983,26 @@ var LavalinkNode = class _LavalinkNode {
2975
2983
  }
2976
2984
  /** private util function for handling the queue end event */
2977
2985
  async queueEnd(player, track, payload) {
2978
- if (player.get("internal_nodeChanging") === true) return;
2986
+ if (player.getData("internal_nodeChanging") === true) return;
2979
2987
  player.queue.current = null;
2980
2988
  player.playing = false;
2981
- player.set("internal_stopPlaying", void 0);
2989
+ player.setData("internal_stopPlaying", void 0);
2982
2990
  this._emitDebugEvent("QueueEnded" /* QueueEnded */, {
2983
2991
  state: "log",
2984
2992
  message: `Queue Ended because no more Tracks were in the Queue, due to EventName: "${payload.type}"`,
2985
2993
  functionLayer: "LavalinkNode > queueEnd()"
2986
2994
  });
2987
- if (typeof this._LManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function" && typeof player.get("internal_autoplayStopPlaying") === "undefined") {
2995
+ if (typeof this._LManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function" && typeof player.getData("internal_autoplayStopPlaying") === "undefined") {
2988
2996
  this._emitDebugEvent("AutoplayExecution" /* AutoplayExecution */, {
2989
2997
  state: "log",
2990
2998
  message: `Now Triggering Autoplay.`,
2991
2999
  functionLayer: "LavalinkNode > queueEnd() > autoplayFunction"
2992
3000
  });
2993
- const previousAutoplayTime = player.get("internal_previousautoplay");
3001
+ const previousAutoplayTime = player.getData("internal_previousautoplay");
2994
3002
  const duration = previousAutoplayTime ? Date.now() - previousAutoplayTime : 0;
2995
- if (!duration || duration > this._LManager.options.playerOptions.minAutoPlayMs || !!player.get("internal_skipped")) {
3003
+ if (!duration || duration > this._LManager.options.playerOptions.minAutoPlayMs || !!player.getData("internal_skipped")) {
2996
3004
  await this._LManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track);
2997
- player.set("internal_previousautoplay", Date.now());
3005
+ player.setData("internal_previousautoplay", Date.now());
2998
3006
  if (player.queue.tracks.length > 0) await queueTrackEnd(player);
2999
3007
  else
3000
3008
  this._emitDebugEvent("AutoplayNoSongsAdded" /* AutoplayNoSongsAdded */, {
@@ -3014,8 +3022,8 @@ var LavalinkNode = class _LavalinkNode {
3014
3022
  });
3015
3023
  }
3016
3024
  }
3017
- player.set("internal_skipped", false);
3018
- player.set("internal_autoplayStopPlaying", void 0);
3025
+ player.setData("internal_skipped", false);
3026
+ player.setData("internal_autoplayStopPlaying", void 0);
3019
3027
  if (track && !track?.pluginInfo?.clientData?.previousTrack) {
3020
3028
  player.queue.previous.unshift(track);
3021
3029
  if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
@@ -3040,11 +3048,11 @@ var LavalinkNode = class _LavalinkNode {
3040
3048
  player,
3041
3049
  this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs
3042
3050
  );
3043
- if (player.get("internal_queueempty")) clearTimeout(player.get("internal_queueempty"));
3044
- player.set(
3051
+ if (player.getData("internal_queueempty")) clearTimeout(player.getData("internal_queueempty"));
3052
+ player.setData(
3045
3053
  "internal_queueempty",
3046
3054
  setTimeout(() => {
3047
- player.set("internal_queueempty", void 0);
3055
+ player.setData("internal_queueempty", void 0);
3048
3056
  if (player.queue.current) {
3049
3057
  return this._LManager.emit("playerQueueEmptyCancel", player);
3050
3058
  }
@@ -3130,13 +3138,13 @@ var LavalinkNode = class _LavalinkNode {
3130
3138
 
3131
3139
  // src/structures/NodeLink.ts
3132
3140
  var NodeLinkNode = class extends LavalinkNode {
3133
- nodeType = "NodeLink";
3141
+ nodeType = "NodeLink" /* NodeLink */;
3134
3142
  constructor(options, manager) {
3135
3143
  super(options, manager);
3136
- if (this.options.nodeType === "Lavalink" && this.constructor.name === "NodeLink") {
3144
+ if (this.options.nodeType === "Lavalink" /* Lavalink */ && (this.constructor.name === "NodeLinkNode" || this.constructor.name === "NodeLink")) {
3137
3145
  return new LavalinkNode(options, manager);
3138
3146
  }
3139
- this.nodeType = "NodeLink";
3147
+ this.nodeType = "NodeLink" /* NodeLink */;
3140
3148
  }
3141
3149
  /**
3142
3150
  * Uses the gapless feature to set the next track to be played.
@@ -3154,6 +3162,20 @@ var NodeLinkNode = class extends LavalinkNode {
3154
3162
  });
3155
3163
  return true;
3156
3164
  }
3165
+ /**
3166
+ * Removes the nextTrackGapLess configuration
3167
+ * @param player current player
3168
+ * @param track if no track provided, it will use the next track from queue
3169
+ */
3170
+ async removeNextTrackGapLess(player) {
3171
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3172
+ await this.updatePlayer({
3173
+ guildId: player.guildId,
3174
+ // @ts-expect-error - nextTrack is not a valid property of LavalinkPlayOptions but for NodeLink it is
3175
+ playerOptions: { nextTrack: { encoded: null } }
3176
+ });
3177
+ return true;
3178
+ }
3157
3179
  /**
3158
3180
  * Retrieves the meaning of a track.
3159
3181
  * @param track
@@ -3463,6 +3485,7 @@ var NodeLinkNode = class extends LavalinkNode {
3463
3485
  LavalinkNode._NodeLinkClass = NodeLinkNode;
3464
3486
 
3465
3487
  // src/structures/NodeManager.ts
3488
+ var import_node_events = require("events");
3466
3489
  var NodeManager = class extends import_node_events.EventEmitter {
3467
3490
  /**
3468
3491
  * Emit an event
@@ -3524,9 +3547,7 @@ var NodeManager = class extends import_node_events.EventEmitter {
3524
3547
  super();
3525
3548
  this.LavalinkManager = LavalinkManager2;
3526
3549
  if (this.LavalinkManager.options.nodes)
3527
- this.LavalinkManager.options.nodes.forEach((node) => {
3528
- this.createNode(node);
3529
- });
3550
+ this.LavalinkManager.options.nodes.forEach((node) => this.createNode(node));
3530
3551
  }
3531
3552
  /**
3532
3553
  * Disconnects all Nodes from lavalink ws sockets
@@ -3587,9 +3608,21 @@ var NodeManager = class extends import_node_events.EventEmitter {
3587
3608
  * @returns The node that was created
3588
3609
  */
3589
3610
  createNode(options) {
3611
+ if (options instanceof NodeLinkNode) {
3612
+ const preExistingNode = this.nodes.get(options.id);
3613
+ if (preExistingNode) return preExistingNode;
3614
+ this.nodes.set(options.id, options);
3615
+ return options;
3616
+ }
3617
+ if (options instanceof LavalinkNode) {
3618
+ const preExistingNode = this.nodes.get(options.id);
3619
+ if (preExistingNode) return preExistingNode;
3620
+ this.nodes.set(options.id, options);
3621
+ return options;
3622
+ }
3590
3623
  if (this.nodes.has(options.id || `${options.host}:${options.port}`))
3591
3624
  return this.nodes.get(options.id || `${options.host}:${options.port}`);
3592
- const newNode = options.nodeType === "NodeLink" ? new NodeLinkNode(options, this) : new LavalinkNode(options, this);
3625
+ const newNode = options.nodeType === "NodeLink" /* NodeLink */ ? new NodeLinkNode(options, this) : new LavalinkNode(options, this);
3593
3626
  this.nodes.set(newNode.id, newNode);
3594
3627
  return newNode;
3595
3628
  }
@@ -3598,48 +3631,57 @@ var NodeManager = class extends import_node_events.EventEmitter {
3598
3631
  * @param sortType The type of sorting to use
3599
3632
  * @returns
3600
3633
  */
3601
- leastUsedNodes(sortType = "players") {
3634
+ leastUsedNodes(sortType = "players", filterForNodeTypes) {
3635
+ const normalizedFilterForNodeTypes = filterForNodeTypes?.length ? filterForNodeTypes : ["Lavalink" /* Lavalink */, "NodeLink" /* NodeLink */];
3602
3636
  const connectedNodes = Array.from(this.nodes.values()).filter((node) => node.connected);
3637
+ const normalizedNodeTypes = new Set(
3638
+ normalizedFilterForNodeTypes.map(
3639
+ (nodeTypeFilter) => Object.values(NodeType).includes(nodeTypeFilter) ? nodeTypeFilter : nodeTypeFilter.nodeType
3640
+ )
3641
+ );
3642
+ const filteredConnectedNodes = connectedNodes.filter((node) => normalizedNodeTypes.has(node.nodeType));
3603
3643
  switch (sortType) {
3604
3644
  case "memory":
3605
3645
  {
3606
- return connectedNodes.sort((a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0));
3646
+ return filteredConnectedNodes.sort(
3647
+ (a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0)
3648
+ );
3607
3649
  }
3608
3650
  break;
3609
3651
  case "cpuLavalink":
3610
3652
  {
3611
- return connectedNodes.sort(
3653
+ return filteredConnectedNodes.sort(
3612
3654
  (a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0)
3613
3655
  );
3614
3656
  }
3615
3657
  break;
3616
3658
  case "cpuSystem":
3617
3659
  {
3618
- return connectedNodes.sort(
3660
+ return filteredConnectedNodes.sort(
3619
3661
  (a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0)
3620
3662
  );
3621
3663
  }
3622
3664
  break;
3623
3665
  case "calls":
3624
3666
  {
3625
- return connectedNodes.sort((a, b) => a.calls - b.calls);
3667
+ return filteredConnectedNodes.sort((a, b) => a.calls - b.calls);
3626
3668
  }
3627
3669
  break;
3628
3670
  case "playingPlayers":
3629
3671
  {
3630
- return connectedNodes.sort(
3672
+ return filteredConnectedNodes.sort(
3631
3673
  (a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0)
3632
3674
  );
3633
3675
  }
3634
3676
  break;
3635
3677
  case "players":
3636
3678
  {
3637
- return connectedNodes.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
3679
+ return filteredConnectedNodes.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
3638
3680
  }
3639
3681
  break;
3640
3682
  default:
3641
3683
  {
3642
- return connectedNodes.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
3684
+ return filteredConnectedNodes.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
3643
3685
  }
3644
3686
  break;
3645
3687
  }
@@ -3672,13 +3714,22 @@ var NodeManager = class extends import_node_events.EventEmitter {
3672
3714
  }
3673
3715
  /**
3674
3716
  * Get a node from the nodeManager
3675
- * @param node The node to get
3717
+ * @param node The node to get either by idetnifier, by class or by enum
3676
3718
  * @returns The node that was retrieved
3677
3719
  */
3678
3720
  getNode(node) {
3721
+ if (!!node && Object.values(NodeType).includes(node)) {
3722
+ return this.leastUsedNodes().filter((node2) => node2.nodeType === node2)[0];
3723
+ }
3724
+ if (!!node && node instanceof NodeLinkNode) {
3725
+ return this.leastUsedNodes().filter((node2) => node2 instanceof NodeLinkNode)[0];
3726
+ }
3727
+ if (!!node && node instanceof LavalinkNode) {
3728
+ return this.leastUsedNodes().filter((node2) => node2 instanceof LavalinkNode)[0];
3729
+ }
3679
3730
  const decodeNode = typeof node === "string" ? this.nodes.get(node) : node;
3680
3731
  if (!decodeNode) return void 0;
3681
- if (decodeNode.nodeType === "NodeLink") return decodeNode;
3732
+ if (decodeNode.nodeType === "NodeLink" /* NodeLink */) return decodeNode;
3682
3733
  return decodeNode;
3683
3734
  }
3684
3735
  };
@@ -3954,8 +4005,8 @@ var FilterManager = class {
3954
4005
  this.player.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
3955
4006
  return;
3956
4007
  }
3957
- privateNot0(value) {
3958
- return typeof value === "number" && value !== 0;
4008
+ privateNot0(value, numToCheckAgains = 0) {
4009
+ return typeof value === "number" && value !== numToCheckAgains;
3959
4010
  }
3960
4011
  getLavalinkFilterData() {
3961
4012
  return this.data.pluginFilters?.["lavalink-filter-plugin"] || {
@@ -4002,7 +4053,8 @@ var FilterManager = class {
4002
4053
  this.filters.lowPass = this.privateNot0(this.data.lowPass?.smoothing);
4003
4054
  this.filters.nodeLinkEcho = this.privateNot0(this.data.echo?.delay) || this.privateNot0(this.data.echo?.feedback) || this.privateNot0(this.data.echo?.mix);
4004
4055
  this.filters.nodeLinkChorus = this.privateNot0(this.data.chorus?.rate) || this.privateNot0(this.data.chorus?.depth) || this.privateNot0(this.data.chorus?.delay) || this.privateNot0(this.data.chorus?.mix) || this.privateNot0(this.data.chorus?.feedback);
4005
- this.filters.nodeLinkCompressor = this.privateNot0(this.data.compressor?.threshold) || this.privateNot0(this.data.compressor?.ratio) || this.privateNot0(this.data.compressor?.attack) || this.privateNot0(this.data.compressor?.release) || this.privateNot0(this.data.compressor?.gain);
4056
+ this.filters.nodeLinkCompressor = this.privateNot0(this.data.compressor?.threshold) || this.privateNot0(this.data.compressor?.ratio, 1) || // here "1" is the default
4057
+ this.privateNot0(this.data.compressor?.attack) || this.privateNot0(this.data.compressor?.release) || this.privateNot0(this.data.compressor?.gain);
4006
4058
  this.filters.nodeLinkHighPass = this.privateNot0(this.data.highPass?.smoothing);
4007
4059
  this.filters.nodeLinkPhaser = this.privateNot0(this.data.phaser?.stages) || this.privateNot0(this.data.phaser?.rate) || this.privateNot0(this.data.phaser?.depth) || this.privateNot0(this.data.phaser?.feedback) || this.privateNot0(this.data.phaser?.mix) || this.privateNot0(this.data.phaser?.minFrequency) || this.privateNot0(this.data.phaser?.maxFrequency);
4008
4060
  this.filters.nodeLinkSpatial = this.privateNot0(this.data.spatial?.depth) || this.privateNot0(this.data.spatial?.rate);
@@ -5365,7 +5417,7 @@ var Player = class {
5365
5417
  */
5366
5418
  constructor(options, LavalinkManager2, dontEmitPlayerCreateEvent) {
5367
5419
  if (typeof options?.customData === "object")
5368
- for (const [key, value] of Object.entries(options.customData)) this.set(key, value);
5420
+ for (const [key, value] of Object.entries(options.customData)) this.setData(key, value);
5369
5421
  this.options = options;
5370
5422
  this.filterManager = new FilterManager(this);
5371
5423
  this.LavalinkManager = LavalinkManager2;
@@ -5474,15 +5526,15 @@ var Player = class {
5474
5526
  * @param options
5475
5527
  */
5476
5528
  async play(options = {}) {
5477
- if (this.get("internal_queueempty")) {
5529
+ if (this.getData("internal_queueempty")) {
5478
5530
  this._emitDebugEvent("PlayerPlayQueueEmptyTimeoutClear" /* PlayerPlayQueueEmptyTimeoutClear */, {
5479
5531
  state: "log",
5480
5532
  message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`,
5481
5533
  functionLayer: "Player > play()"
5482
5534
  });
5483
5535
  this.LavalinkManager.emit("playerQueueEmptyCancel", this);
5484
- clearTimeout(this.get("internal_queueempty"));
5485
- this.set("internal_queueempty", void 0);
5536
+ clearTimeout(this.getData("internal_queueempty"));
5537
+ this.setData("internal_queueempty", void 0);
5486
5538
  }
5487
5539
  if (options?.clientTrack && (this.LavalinkManager.utils.isTrack(options?.clientTrack) || this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))) {
5488
5540
  if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack)) {
@@ -5830,7 +5882,7 @@ var Player = class {
5830
5882
  }
5831
5883
  if (!this.playing && !this.queue.current) return this.play(), this;
5832
5884
  const now = performance.now();
5833
- this.set("internal_skipped", true);
5885
+ this.setData("internal_skipped", true);
5834
5886
  await this.node.updatePlayer({
5835
5887
  guildId: this.guildId,
5836
5888
  playerOptions: { track: { encoded: null }, paused: false }
@@ -5843,14 +5895,20 @@ var Player = class {
5843
5895
  * @returns
5844
5896
  */
5845
5897
  async stopPlaying(clearQueue = true, executeAutoplay = false) {
5846
- this.set("internal_stopPlaying", true);
5898
+ this.setData("internal_stopPlaying", true);
5847
5899
  if (this.queue.tracks.length && clearQueue === true) await this.queue.splice(0, this.queue.tracks.length);
5848
- if (executeAutoplay === false) this.set("internal_autoplayStopPlaying", true);
5849
- else this.set("internal_autoplayStopPlaying", void 0);
5900
+ if (executeAutoplay === false) this.setData("internal_autoplayStopPlaying", true);
5901
+ else this.setData("internal_autoplayStopPlaying", void 0);
5850
5902
  const now = performance.now();
5851
5903
  await this.node.updatePlayer({
5852
5904
  guildId: this.guildId,
5853
- playerOptions: { track: { encoded: null } }
5905
+ playerOptions: this.node.isNodeLink() ? {
5906
+ track: { encoded: null },
5907
+ // @ts-expect-error - nextTrack is not a valid property of LavalinkPlayOptions but for NodeLink it is
5908
+ nextTrack: { encoded: null }
5909
+ } : {
5910
+ track: { encoded: null }
5911
+ }
5854
5912
  });
5855
5913
  this.paused = false;
5856
5914
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
@@ -5921,11 +5979,11 @@ var Player = class {
5921
5979
  console.log(
5922
5980
  `Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`
5923
5981
  );
5924
- if (this.get("internal_queueempty")) {
5925
- clearTimeout(this.get("internal_queueempty"));
5926
- this.set("internal_queueempty", void 0);
5982
+ if (this.getData("internal_queueempty")) {
5983
+ clearTimeout(this.getData("internal_queueempty"));
5984
+ this.setData("internal_queueempty", void 0);
5927
5985
  }
5928
- if (this.get("internal_destroystatus") === true) {
5986
+ if (this.getData("internal_destroystatus") === true) {
5929
5987
  this._emitDebugEvent("PlayerDestroyingSomewhereElse" /* PlayerDestroyingSomewhereElse */, {
5930
5988
  state: "warn",
5931
5989
  message: `Player is already destroying somewhere else..`,
@@ -5937,9 +5995,9 @@ var Player = class {
5937
5995
  );
5938
5996
  return;
5939
5997
  }
5940
- this.set("internal_destroystatus", true);
5998
+ this.setData("internal_destroystatus", true);
5941
5999
  if (disconnect) await this.disconnect(true);
5942
- else this.set("internal_destroywithoutdisconnect", true);
6000
+ else this.setData("internal_destroywithoutdisconnect", true);
5943
6001
  await this.queue.utils.destroy();
5944
6002
  this.LavalinkManager.deletePlayer(this.guildId);
5945
6003
  await this.node.destroyPlayer(this.guildId);
@@ -6014,7 +6072,7 @@ var Player = class {
6014
6072
  if (!updateNode) throw new Error("Could not find the new Node");
6015
6073
  if (!updateNode.connected) throw new Error("The provided Node is not active or disconnected");
6016
6074
  if (this.node.id === updateNode.id) throw new Error("Player is already on the provided Node");
6017
- if (this.get("internal_nodeChanging") === true)
6075
+ if (this.getData("internal_nodeChanging") === true)
6018
6076
  throw new Error("Player is already changing the node please wait");
6019
6077
  if (checkSources) {
6020
6078
  const isDefaultSource = () => {
@@ -6052,7 +6110,7 @@ var Player = class {
6052
6110
  const currentTrack = this.queue.current;
6053
6111
  if (!this.voice.endpoint || !this.voice.sessionId || !this.voice.token)
6054
6112
  throw new Error("Voice Data is missing, can't change the node");
6055
- this.set("internal_nodeChanging", true);
6113
+ this.setData("internal_nodeChanging", true);
6056
6114
  if (this.node.connected) await this.node.destroyPlayer(this.guildId);
6057
6115
  this.node = updateNode;
6058
6116
  const now = performance.now();
@@ -6060,7 +6118,7 @@ var Player = class {
6060
6118
  await this.connect();
6061
6119
  const hasSponsorBlock = !this.node._checkForPlugins || this.node.info?.plugins?.find((v) => v.name === "sponsorblock-plugin");
6062
6120
  if (hasSponsorBlock) {
6063
- const sponsorBlockCategories = this.get("internal_sponsorBlockCategories");
6121
+ const sponsorBlockCategories = this.getData("internal_sponsorBlockCategories");
6064
6122
  if (Array.isArray(sponsorBlockCategories) && sponsorBlockCategories.length) {
6065
6123
  await this.setSponsorBlock(sponsorBlockCategories).catch((error) => {
6066
6124
  this._emitDebugEvent("PlayerChangeNode" /* PlayerChangeNode */, {
@@ -6111,7 +6169,7 @@ var Player = class {
6111
6169
  });
6112
6170
  throw new Error(`Failed to change the node: ${error}`);
6113
6171
  } finally {
6114
- this.set("internal_nodeChanging", void 0);
6172
+ this.setData("internal_nodeChanging", void 0);
6115
6173
  }
6116
6174
  }
6117
6175
  /**
@@ -6310,9 +6368,11 @@ var LavalinkManager = class _LavalinkManager extends import_node_events2.EventEm
6310
6368
  throw new SyntaxError("ManagerOption.autoSkipOnResolveError must be either false | true aka boolean");
6311
6369
  if (options?.emitNewSongsOnly && typeof options?.emitNewSongsOnly !== "boolean")
6312
6370
  throw new SyntaxError("ManagerOption.emitNewSongsOnly must be either false | true aka boolean");
6313
- if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every((node) => this.utils.isNodeOptions(node)))
6371
+ if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every(
6372
+ (node) => node instanceof NodeLinkNode || node instanceof LavalinkNode || this.utils.isNodeOptions(node)
6373
+ ))
6314
6374
  throw new SyntaxError(
6315
- "ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node"
6375
+ "ManagerOption.nodes must be an Array of NodeOptions or the Node-Classes 'NodeLinkNode' or 'LavalinkNode' and is required of at least 1 Node"
6316
6376
  );
6317
6377
  if (options?.queueOptions?.queueStore) {
6318
6378
  const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueStore));
@@ -6368,48 +6428,50 @@ var LavalinkManager = class _LavalinkManager extends import_node_events2.EventEm
6368
6428
  * port: 2333,
6369
6429
  * id: "testnode"
6370
6430
  * },
6431
+ * // you can also use the util like this, and it will return a valid node option object. must start with: lavalink:// | nodelink://
6432
+ * // parseLavalinkConnUrl("nodelink://<nodeId>:<nodeAuthorization(Password)>@<NodeHost>:<NodePort>")
6371
6433
  * sendToShard(guildId, payload) => client.guilds.cache.get(guildId)?.shard?.send(payload),
6372
- * client: {
6373
- * id: process.env.CLIENT_ID,
6374
- * username: "TESTBOT"
6375
- * },
6376
- * // optional Options:
6377
- * autoSkip: true,
6378
- * playerOptions: {
6379
- * applyVolumeAsFilter: false,
6380
- * clientBasedPositionUpdateInterval: 150,
6381
- * defaultSearchPlatform: "ytmsearch",
6382
- * allowCustomSources: false,
6383
- * volumeDecrementer: 0.75,
6384
- * //requesterTransformer: YourRequesterTransformerFunction,
6385
- * onDisconnect: {
6386
- * autoReconnect: true,
6387
- * destroyPlayer: false
6388
- * },
6389
- * onEmptyQueue: {
6390
- * destroyAfterMs: 30_000,
6391
- * //autoPlayFunction: YourAutoplayFunction,
6392
- * },
6393
- * useUnresolvedData: true
6434
+ * ],
6435
+ * client: {
6436
+ * id: process.env.CLIENT_ID,
6437
+ * username: "TESTBOT"
6438
+ * },
6439
+ * // optional Options:
6440
+ * autoSkip: true,
6441
+ * playerOptions: {
6442
+ * applyVolumeAsFilter: false,
6443
+ * clientBasedPositionUpdateInterval: 150,
6444
+ * defaultSearchPlatform: "ytmsearch",
6445
+ * allowCustomSources: false,
6446
+ * volumeDecrementer: 0.75,
6447
+ * //requesterTransformer: YourRequesterTransformerFunction,
6448
+ * onDisconnect: {
6449
+ * autoReconnect: true,
6450
+ * destroyPlayer: false
6394
6451
  * },
6395
- * queueOptions: {
6396
- * maxPreviousTracks: 25,
6397
- * //queueStore: yourCustomQueueStoreManagerClass,
6398
- * //queueChangesWatcher: yourCustomQueueChangesWatcherClass
6452
+ * onEmptyQueue: {
6453
+ * destroyAfterMs: 30_000,
6454
+ * //autoPlayFunction: YourAutoplayFunction,
6399
6455
  * },
6400
- * linksBlacklist: [],
6401
- * linksWhitelist: [],
6402
- * advancedOptions: {
6403
- * maxFilterFixDuration: 600_000,
6404
- * debugOptions: {
6405
- * noAudio: false,
6406
- * playerDestroy: {
6407
- * dontThrowError: false,
6408
- * debugLogs: false
6409
- * }
6456
+ * useUnresolvedData: true
6457
+ * },
6458
+ * queueOptions: {
6459
+ * maxPreviousTracks: 25,
6460
+ * //queueStore: yourCustomQueueStoreManagerClass,
6461
+ * //queueChangesWatcher: yourCustomQueueChangesWatcherClass
6462
+ * },
6463
+ * linksBlacklist: [],
6464
+ * linksWhitelist: [],
6465
+ * advancedOptions: {
6466
+ * maxFilterFixDuration: 600_000,
6467
+ * debugOptions: {
6468
+ * noAudio: false,
6469
+ * playerDestroy: {
6470
+ * dontThrowError: false,
6471
+ * debugLogs: false
6410
6472
  * }
6411
6473
  * }
6412
- * ]
6474
+ * }
6413
6475
  * })
6414
6476
  * ```
6415
6477
  */
@@ -6501,7 +6563,7 @@ var LavalinkManager = class _LavalinkManager extends import_node_events2.EventEm
6501
6563
  deletePlayer(guildId) {
6502
6564
  const oldPlayer = this.getPlayer(guildId);
6503
6565
  if (!oldPlayer) return;
6504
- if (typeof oldPlayer.voiceChannelId === "string" && oldPlayer.connected && !oldPlayer.get("internal_destroywithoutdisconnect")) {
6566
+ if (typeof oldPlayer.voiceChannelId === "string" && oldPlayer.connected && !oldPlayer.getData("internal_destroywithoutdisconnect")) {
6505
6567
  if (!this.options?.advancedOptions?.debugOptions?.playerDestroy?.dontThrowError)
6506
6568
  throw new Error(
6507
6569
  `Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player ${safeStringify(oldPlayer.toJSON?.())}`
@@ -6648,7 +6710,7 @@ var LavalinkManager = class _LavalinkManager extends import_node_events2.EventEm
6648
6710
  );
6649
6711
  return;
6650
6712
  }
6651
- if (player.get("internal_destroystatus") === true) {
6713
+ if (player.getData("internal_destroystatus") === true) {
6652
6714
  this._debugNoAudio("warn", "LavalinkManager > sendRawData()", {
6653
6715
  message: "Player is in a destroying state. can't signal the voice states"
6654
6716
  });
@@ -6818,6 +6880,7 @@ var LavalinkManager = class _LavalinkManager extends import_node_events2.EventEm
6818
6880
  NodeLinkNode,
6819
6881
  NodeManager,
6820
6882
  NodeSymbol,
6883
+ NodeType,
6821
6884
  Player,
6822
6885
  Queue,
6823
6886
  QueueSaver,