lavalink-client 2.8.0 → 2.9.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.
Files changed (6) hide show
  1. package/README.md +726 -518
  2. package/dist/index.d.mts +2427 -1893
  3. package/dist/index.d.ts +2427 -1893
  4. package/dist/index.js +1776 -566
  5. package/dist/index.mjs +1773 -566
  6. package/package.json +79 -81
package/dist/index.mjs CHANGED
@@ -71,7 +71,16 @@ var DisconnectReasons = /* @__PURE__ */ ((DisconnectReasons2) => {
71
71
  DisconnectReasons2["DisconnectAllNodes"] = "DisconnectAllNodes";
72
72
  return DisconnectReasons2;
73
73
  })(DisconnectReasons || {});
74
- var validSponsorBlocks = ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "filler"];
74
+ var validSponsorBlocks = [
75
+ "sponsor",
76
+ "selfpromo",
77
+ "interaction",
78
+ "intro",
79
+ "outro",
80
+ "preview",
81
+ "music_offtopic",
82
+ "filler"
83
+ ];
75
84
  var audioOutputsData = {
76
85
  mono: {
77
86
  // totalLeft: 1, totalRight: 1
@@ -302,6 +311,33 @@ var EQList = {
302
311
  { band: 14, gain: -0.35 }
303
312
  ]
304
313
  };
314
+ var RecommendationsStrings = {
315
+ highCPULoad: (cpuLoad) => `High CPU load (${(cpuLoad * 100).toFixed(1)}%). Consider reducing player count or upgrading CPU.`,
316
+ highSystemLoad: (systemLoad) => `High system load (${(systemLoad * 100).toFixed(1)}%). Check other processes on the server.`,
317
+ highMemoryUsage: (memoryUsagePercent) => `High memory usage (${memoryUsagePercent.toFixed(1)}%). Consider increasing allocated memory or reducing player count.`,
318
+ frameDeficit: (frameDeficit) => `Frame deficit detected (${frameDeficit}). Audio quality may be affected. Check network and CPU.`,
319
+ highLatency: (ping) => `High latency (${ping}ms). Check network connection to the node.`,
320
+ nodeRestart: "Node restart recommended to clear memory and reset connections.",
321
+ highPlayercount: (players) => `High player count (${players}). Consider load balancing across multiple nodes.`,
322
+ nodeOffline: "Node is offline or disconnected",
323
+ checkConnectivity: "Check node connectivity and restart if needed"
324
+ };
325
+ var NodeLinkExclusiveEvents = [
326
+ "PlayerCreatedEvent",
327
+ "PlayerDestroyedEvent",
328
+ "PlayerConnectedEvent",
329
+ "PlayerReconnectingEvent",
330
+ "VolumeChangedEvent",
331
+ "FiltersChangedEvent",
332
+ "SeekEvent",
333
+ "PauseEvent",
334
+ "ConnectionStatusEvent",
335
+ "MixStartedEvent",
336
+ "MixEndedEvent",
337
+ "LyricsFoundEvent",
338
+ "LyricsLineEvent",
339
+ "LyricsNotFoundEvent"
340
+ ];
305
341
 
306
342
  // src/structures/NodeManager.ts
307
343
  import { EventEmitter } from "events";
@@ -327,99 +363,99 @@ import { isRegExp } from "util/types";
327
363
  var DefaultSources = {
328
364
  // youtubemusic
329
365
  "youtube music": "ytmsearch",
330
- "youtubemusic": "ytmsearch",
331
- "ytmsearch": "ytmsearch",
332
- "ytm": "ytmsearch",
333
- "musicyoutube": "ytmsearch",
366
+ youtubemusic: "ytmsearch",
367
+ ytmsearch: "ytmsearch",
368
+ ytm: "ytmsearch",
369
+ musicyoutube: "ytmsearch",
334
370
  "music youtube": "ytmsearch",
335
371
  // youtube
336
- "youtube": "ytsearch",
337
- "yt": "ytsearch",
338
- "ytsearch": "ytsearch",
372
+ youtube: "ytsearch",
373
+ yt: "ytsearch",
374
+ ytsearch: "ytsearch",
339
375
  // soundcloud
340
- "soundcloud": "scsearch",
341
- "scsearch": "scsearch",
342
- "sc": "scsearch",
376
+ soundcloud: "scsearch",
377
+ scsearch: "scsearch",
378
+ sc: "scsearch",
343
379
  // apple music
344
380
  "apple music": "amsearch",
345
- "apple": "amsearch",
346
- "applemusic": "amsearch",
347
- "amsearch": "amsearch",
348
- "am": "amsearch",
349
- "musicapple": "amsearch",
381
+ apple: "amsearch",
382
+ applemusic: "amsearch",
383
+ amsearch: "amsearch",
384
+ am: "amsearch",
385
+ musicapple: "amsearch",
350
386
  "music apple": "amsearch",
351
387
  // spotify
352
- "spotify": "spsearch",
353
- "spsearch": "spsearch",
354
- "sp": "spsearch",
388
+ spotify: "spsearch",
389
+ spsearch: "spsearch",
390
+ sp: "spsearch",
355
391
  "spotify.com": "spsearch",
356
- "spotifycom": "spsearch",
357
- "sprec": "sprec",
358
- "spsuggestion": "sprec",
392
+ spotifycom: "spsearch",
393
+ sprec: "sprec",
394
+ spsuggestion: "sprec",
359
395
  // deezer
360
- "deezer": "dzsearch",
361
- "dz": "dzsearch",
362
- "dzsearch": "dzsearch",
363
- "dzisrc": "dzisrc",
364
- "dzrec": "dzrec",
396
+ deezer: "dzsearch",
397
+ dz: "dzsearch",
398
+ dzsearch: "dzsearch",
399
+ dzisrc: "dzisrc",
400
+ dzrec: "dzrec",
365
401
  // yandexmusic
366
402
  "yandex music": "ymsearch",
367
- "yandexmusic": "ymsearch",
368
- "yandex": "ymsearch",
369
- "ymsearch": "ymsearch",
370
- "ymrec": "ymrec",
403
+ yandexmusic: "ymsearch",
404
+ yandex: "ymsearch",
405
+ ymsearch: "ymsearch",
406
+ ymrec: "ymrec",
371
407
  // VK Music (lavasrc)
372
- "vksearch": "vksearch",
373
- "vkmusic": "vksearch",
408
+ vksearch: "vksearch",
409
+ vkmusic: "vksearch",
374
410
  "vk music": "vksearch",
375
- "vkrec": "vkrec",
376
- "vk": "vksearch",
411
+ vkrec: "vkrec",
412
+ vk: "vksearch",
377
413
  // Qobuz (lavasrc)
378
- "qbsearch": "qbsearch",
379
- "qobuz": "qbsearch",
380
- "qbisrc": "qbisrc",
381
- "qbrec": "qbrec",
414
+ qbsearch: "qbsearch",
415
+ qobuz: "qbsearch",
416
+ qbisrc: "qbisrc",
417
+ qbrec: "qbrec",
382
418
  // pandora (lavasrc)
383
- "pandora": "pdsearch",
384
- "pd": "pdsearch",
385
- "pdsearch": "pdsearch",
386
- "pdisrc": "pdisrc",
387
- "pdrec": "pdrec",
419
+ pandora: "pdsearch",
420
+ pd: "pdsearch",
421
+ pdsearch: "pdsearch",
422
+ pdisrc: "pdisrc",
423
+ pdrec: "pdrec",
388
424
  "pandora music": "pdsearch",
389
- "pandoramusic": "pdsearch",
425
+ pandoramusic: "pdsearch",
390
426
  // speak PLUGIN
391
- "speak": "speak",
392
- "tts": "tts",
393
- "ftts": "ftts",
394
- "flowery": "ftts",
427
+ speak: "speak",
428
+ tts: "tts",
429
+ ftts: "ftts",
430
+ flowery: "ftts",
395
431
  "flowery.tts": "ftts",
396
- "flowerytts": "ftts",
432
+ flowerytts: "ftts",
397
433
  // Client sided search platforms (after lavalinkv4.0.6 it will search via bcsearch on the node itself)
398
- "bandcamp": "bcsearch",
399
- "bc": "bcsearch",
400
- "bcsearch": "bcsearch",
434
+ bandcamp: "bcsearch",
435
+ bc: "bcsearch",
436
+ bcsearch: "bcsearch",
401
437
  // other searches:
402
- "phsearch": "phsearch",
403
- "pornhub": "phsearch",
404
- "porn": "phsearch",
438
+ phsearch: "phsearch",
439
+ pornhub: "phsearch",
440
+ porn: "phsearch",
405
441
  // local files
406
- "local": "local",
442
+ local: "local",
407
443
  // http requests
408
- "http": "http",
409
- "https": "https",
410
- "link": "link",
411
- "uri": "uri",
444
+ http: "http",
445
+ https: "https",
446
+ link: "link",
447
+ uri: "uri",
412
448
  // tidal
413
- "tidal": "tdsearch",
414
- "td": "tdsearch",
449
+ tidal: "tdsearch",
450
+ td: "tdsearch",
415
451
  "tidal music": "tdsearch",
416
- "tdsearch": "tdsearch",
417
- "tdrec": "tdrec",
452
+ tdsearch: "tdsearch",
453
+ tdrec: "tdrec",
418
454
  // jiosaavn
419
- "jiosaavn": "jssearch",
420
- "js": "jssearch",
421
- "jssearch": "jssearch",
422
- "jsrec": "jsrec"
455
+ jiosaavn: "jssearch",
456
+ js: "jssearch",
457
+ jssearch: "jssearch",
458
+ jsrec: "jsrec"
423
459
  };
424
460
  var LavalinkPlugins = {
425
461
  DuncteBot_Plugin: "DuncteBot-plugin",
@@ -470,11 +506,11 @@ var SourceLinksRegexes = {
470
506
  /** From jiosaavn-plugin */
471
507
  jiosaavn: /(https?:\/\/)(www\.)?jiosaavn\.com\/(?<type>song|album|featured|artist)\/([a-zA-Z0-9-_/,]+)/,
472
508
  /** From pandora */
473
- PandoraTrackRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/artist\/[\w\-]+(?:\/[\w\-]+)*\/(?<identifier>TR[A-Za-z0-9]+)(?:[?#].*)?$/,
474
- PandoraAlbumRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/artist\/[\w\-]+(?:\/[\w\-]+)*\/(?<identifier>AL[A-Za-z0-9]+)(?:[?#].*)?$/,
475
- PandoraArtistRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/artist\/[\w\-]+\/(?<identifier>AR[A-Za-z0-9]+)(?:[?#].*)?$/,
509
+ PandoraTrackRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/artist\/[\w-]+(?:\/[\w-]+)*\/(?<identifier>TR[A-Za-z0-9]+)(?:[?#].*)?$/,
510
+ PandoraAlbumRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/artist\/[\w-]+(?:\/[\w-]+)*\/(?<identifier>AL[A-Za-z0-9]+)(?:[?#].*)?$/,
511
+ PandoraArtistRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/artist\/[\w-]+\/(?<identifier>AR[A-Za-z0-9]+)(?:[?#].*)?$/,
476
512
  PandoraPlaylistRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/playlist\/(?<identifier>PL:[\d:]+)(?:[?#].*)?$/,
477
- AllPandoraRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/(?:playlist\/(?<playlistId>PL:[\d:]+)|artist\/[\w\-]+(?:\/[\w\-]+)*\/(?<identifier>(?:TR|AL|AR)[A-Za-z0-9]+))(?:[?#].*)?$/,
513
+ AllPandoraRegex: /^@?(?:https?:\/\/)?(?:www\.)?pandora\.com\/(?:playlist\/(?<playlistId>PL:[\d:]+)|artist\/[\w-]+(?:\/[\w-]+)*\/(?<identifier>(?:TR|AL|AR)[A-Za-z0-9]+))(?:[?#].*)?$/,
478
514
  /** FROM DUNCTE BOT PLUGIN */
479
515
  tiktok: /https:\/\/www\.tiktok\.com\//,
480
516
  mixcloud: /https:\/\/www\.mixcloud\.com\//,
@@ -483,13 +519,14 @@ var SourceLinksRegexes = {
483
519
  };
484
520
 
485
521
  // src/structures/Utils.ts
486
- var TrackSymbol = Symbol("LC-Track");
487
- var UnresolvedTrackSymbol = Symbol("LC-Track-Unresolved");
488
- var QueueSymbol = Symbol("LC-Queue");
489
- var NodeSymbol = Symbol("LC-Node");
522
+ var TrackSymbol = /* @__PURE__ */ Symbol("LC-Track");
523
+ var UnresolvedTrackSymbol = /* @__PURE__ */ Symbol("LC-Track-Unresolved");
524
+ var QueueSymbol = /* @__PURE__ */ Symbol("LC-Queue");
525
+ var NodeSymbol = /* @__PURE__ */ Symbol("LC-Node");
490
526
  var escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
491
527
  function parseLavalinkConnUrl(connectionUrl) {
492
- if (!connectionUrl.startsWith("lavalink://")) throw new Error(`ConnectionUrl (${connectionUrl}) must start with 'lavalink://'`);
528
+ if (!connectionUrl.startsWith("lavalink://"))
529
+ throw new Error(`ConnectionUrl (${connectionUrl}) must start with 'lavalink://'`);
493
530
  const parsed = new URL2(connectionUrl);
494
531
  return {
495
532
  authorization: parsed.password,
@@ -503,14 +540,27 @@ var ManagerUtils = class {
503
540
  constructor(LavalinkManager2) {
504
541
  this.LavalinkManager = LavalinkManager2;
505
542
  }
543
+ /**
544
+ * Builds a pluginInfo object based on the provided data, extracting relevant information from the data and clientData parameters. This function is used to construct the pluginInfo property for tracks, allowing for consistent handling of plugin-related information across different track sources and formats.
545
+ * @param data
546
+ * @param clientData
547
+ * @returns
548
+ */
506
549
  buildPluginInfo(data, clientData = {}) {
507
550
  return {
508
551
  clientData,
509
552
  ...data.pluginInfo || data.plugin
510
553
  };
511
554
  }
555
+ /**
556
+ * Builds a Track object from the provided data and requester information. It validates the presence of required properties in the data, transforms the requester using a custom transformer function if provided, and constructs a Track object with the appropriate properties and plugin information. The function also includes error handling to ensure that the input data is valid and provides debug information if track building fails.
557
+ * @param data
558
+ * @param requester
559
+ * @returns
560
+ */
512
561
  buildTrack(data, requester) {
513
- if (!data?.encoded || typeof data.encoded !== "string") throw new RangeError("Argument 'data.encoded' must be present.");
562
+ if (!data?.encoded || typeof data.encoded !== "string")
563
+ throw new RangeError("Argument 'data.encoded' must be present.");
514
564
  if (!data.info) throw new RangeError("Argument 'data.info' must be present.");
515
565
  try {
516
566
  let transformedRequester = typeof requester === "object" ? this.getTransformedRequester(requester) : void 0;
@@ -558,8 +608,7 @@ var ManagerUtils = class {
558
608
  * @param requester
559
609
  */
560
610
  buildUnresolvedTrack(query, requester) {
561
- if (typeof query === "undefined")
562
- throw new RangeError('Argument "query" must be present.');
611
+ if (typeof query === "undefined") throw new RangeError('Argument "query" must be present.');
563
612
  const unresolvedTrack = {
564
613
  encoded: query.encoded || void 0,
565
614
  info: query.info ? query.info : query.title ? query : void 0,
@@ -575,7 +624,10 @@ var ManagerUtils = class {
575
624
  }
576
625
  };
577
626
  if (!this.isUnresolvedTrack(unresolvedTrack)) throw SyntaxError("Could not build Unresolved Track");
578
- Object.defineProperty(unresolvedTrack, UnresolvedTrackSymbol, { configurable: true, value: true });
627
+ Object.defineProperty(unresolvedTrack, UnresolvedTrackSymbol, {
628
+ configurable: true,
629
+ value: true
630
+ });
579
631
  return unresolvedTrack;
580
632
  }
581
633
  /**
@@ -587,9 +639,27 @@ var ManagerUtils = class {
587
639
  const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(data));
588
640
  if (!keys.includes("constructor")) return false;
589
641
  if (!keys.length) return false;
590
- if (!["connect", "destroy", "destroyPlayer", "fetchAllPlayers", "fetchInfo", "fetchPlayer", "fetchStats", "fetchVersion", "request", "updatePlayer", "updateSession"].every((v) => keys.includes(v))) return false;
642
+ if (![
643
+ "connect",
644
+ "destroy",
645
+ "destroyPlayer",
646
+ "fetchAllPlayers",
647
+ "fetchInfo",
648
+ "fetchPlayer",
649
+ "fetchStats",
650
+ "fetchVersion",
651
+ "request",
652
+ "updatePlayer",
653
+ "updateSession"
654
+ ].every((v) => keys.includes(v)))
655
+ return false;
591
656
  return true;
592
657
  }
658
+ /**
659
+ * Gets the transformed requester based on the LavalinkManager options. If a custom requester transformer function is provided in the player options, it applies that function to the requester; otherwise, it returns the requester as is. The function also includes error handling to catch any exceptions that may occur during the transformation process and emits a debug event if the transformation fails.
660
+ * @param requester
661
+ * @returns
662
+ */
593
663
  getTransformedRequester(requester) {
594
664
  try {
595
665
  return typeof this.LavalinkManager?.options?.playerOptions?.requesterTransformer === "function" ? this.LavalinkManager?.options?.playerOptions?.requesterTransformer(requester) : requester;
@@ -617,11 +687,16 @@ var ManagerUtils = class {
617
687
  if ("secure" in data && typeof data.secure !== "boolean" && data.secure !== void 0) return false;
618
688
  if ("sessionId" in data && typeof data.sessionId !== "string" && data.sessionId !== void 0) return false;
619
689
  if ("id" in data && typeof data.id !== "string" && data.id !== void 0) return false;
620
- if ("regions" in data && (!Array.isArray(data.regions) || !data.regions.every((v) => typeof v === "string") && data.regions !== void 0)) return false;
621
- if ("poolOptions" in data && typeof data.poolOptions !== "object" && data.poolOptions !== void 0) return false;
622
- if ("retryAmount" in data && (typeof data.retryAmount !== "number" || isNaN(data.retryAmount) || data.retryAmount <= 0 && data.retryAmount !== void 0)) return false;
623
- if ("retryDelay" in data && (typeof data.retryDelay !== "number" || isNaN(data.retryDelay) || data.retryDelay <= 0 && data.retryDelay !== void 0)) return false;
624
- if ("requestTimeout" in data && (typeof data.requestTimeout !== "number" || isNaN(data.requestTimeout) || data.requestTimeout <= 0 && data.requestTimeout !== void 0)) return false;
690
+ if ("regions" in data && (!Array.isArray(data.regions) || !data.regions.every((v) => typeof v === "string") && data.regions !== void 0))
691
+ return false;
692
+ if ("poolOptions" in data && typeof data.poolOptions !== "object" && data.poolOptions !== void 0)
693
+ return false;
694
+ if ("retryAmount" in data && (typeof data.retryAmount !== "number" || isNaN(data.retryAmount) || data.retryAmount <= 0 && data.retryAmount !== void 0))
695
+ return false;
696
+ if ("retryDelay" in data && (typeof data.retryDelay !== "number" || isNaN(data.retryDelay) || data.retryDelay <= 0 && data.retryDelay !== void 0))
697
+ return false;
698
+ if ("requestTimeout" in data && (typeof data.requestTimeout !== "number" || isNaN(data.requestTimeout) || data.requestTimeout <= 0 && data.requestTimeout !== void 0))
699
+ return false;
625
700
  return true;
626
701
  }
627
702
  /**
@@ -673,6 +748,12 @@ var ManagerUtils = class {
673
748
  isUnresolvedTrackQuery(data) {
674
749
  return typeof data === "object" && !("info" in data) && typeof data.title === "string";
675
750
  }
751
+ /**
752
+ * Gets the closest track by resolving the provided UnresolvedTrack using the getClosestTrack function. It includes error handling to catch any exceptions that may occur during the resolution process and emits a debug event if the resolution fails. The function returns a Promise that resolves to a Track object if successful, or undefined if no closest track is found.
753
+ * @param data
754
+ * @param player
755
+ * @returns
756
+ */
676
757
  async getClosestTrack(data, player) {
677
758
  try {
678
759
  return getClosestTrack(data, player);
@@ -688,11 +769,20 @@ var ManagerUtils = class {
688
769
  throw e;
689
770
  }
690
771
  }
772
+ /**
773
+ * Validates the query string against various criteria, including checking for empty strings, length limits for specific sources, blacklisted links or words, and ensuring that the Lavalink node has the necessary source managers enabled for the provided query. The function also includes debug event emissions to assist with troubleshooting and understanding the validation process.
774
+ * @param node
775
+ * @param queryString
776
+ * @param sourceString
777
+ * @returns
778
+ */
691
779
  validateQueryString(node, queryString, sourceString) {
692
780
  if (!node.info) throw new Error("No Lavalink Node was provided");
693
- if (this.LavalinkManager.options?.autoChecks?.sourcesValidations && !node.info.sourceManagers?.length) throw new Error("Lavalink Node, has no sourceManagers enabled");
781
+ if (node._checkForSources && !node.info.sourceManagers?.length)
782
+ throw new Error("Lavalink Node, has no sourceManagers enabled");
694
783
  if (!queryString.trim().length) throw new Error(`Query string is empty, please provide a valid query string.`);
695
- if (sourceString === "speak" && queryString.length > 100) throw new Error(`Query is speak, which is limited to 100 characters.`);
784
+ if (sourceString === "speak" && queryString.length > 100)
785
+ throw new Error(`Query is speak, which is limited to 100 characters.`);
696
786
  if (this.LavalinkManager.options?.linksBlacklist?.length > 0) {
697
787
  if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
698
788
  this.LavalinkManager.emit("debug", "ValidatingBlacklistLinks" /* ValidatingBlacklistLinks */, {
@@ -701,12 +791,15 @@ var ManagerUtils = class {
701
791
  functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()"
702
792
  });
703
793
  }
704
- if (this.LavalinkManager.options?.linksBlacklist.some((v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString))) {
794
+ if (this.LavalinkManager.options?.linksBlacklist.some(
795
+ (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString)
796
+ )) {
705
797
  throw new Error(`Query string contains a link / word which is blacklisted.`);
706
798
  }
707
799
  }
708
800
  if (!/^https?:\/\//.test(queryString)) return;
709
- else if (this.LavalinkManager.options?.linksAllowed === false) throw new Error("Using links to make a request is not allowed.");
801
+ else if (this.LavalinkManager.options?.linksAllowed === false)
802
+ throw new Error("Using links to make a request is not allowed.");
710
803
  if (this.LavalinkManager.options?.linksWhitelist?.length > 0) {
711
804
  if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
712
805
  this.LavalinkManager.emit("debug", "ValidatingWhitelistLinks" /* ValidatingWhitelistLinks */, {
@@ -715,11 +808,13 @@ var ManagerUtils = class {
715
808
  functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()"
716
809
  });
717
810
  }
718
- if (!this.LavalinkManager.options?.linksWhitelist.some((v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString))) {
811
+ if (!this.LavalinkManager.options?.linksWhitelist.some(
812
+ (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString)
813
+ )) {
719
814
  throw new Error(`Query string contains a link / word which isn't whitelisted.`);
720
815
  }
721
816
  }
722
- if (!this.LavalinkManager.options?.autoChecks?.sourcesValidations) return;
817
+ if (!node._checkForSources) return;
723
818
  if ((SourceLinksRegexes.YoutubeMusicRegex.test(queryString) || SourceLinksRegexes.YoutubeRegex.test(queryString)) && !node.info?.sourceManagers?.includes("youtube")) {
724
819
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'youtube' enabled");
725
820
  }
@@ -727,7 +822,9 @@ var ManagerUtils = class {
727
822
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'soundcloud' enabled");
728
823
  }
729
824
  if (SourceLinksRegexes.bandcamp.test(queryString) && !node.info?.sourceManagers?.includes("bandcamp")) {
730
- throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'bandcamp' enabled (introduced with lavaplayer 2.2.0 or lavalink 4.0.6)");
825
+ throw new Error(
826
+ "Query / Link Provided for this Source but Lavalink Node has not 'bandcamp' enabled (introduced with lavaplayer 2.2.0 or lavalink 4.0.6)"
827
+ );
731
828
  }
732
829
  if (SourceLinksRegexes.TwitchTv.test(queryString) && !node.info?.sourceManagers?.includes("twitch")) {
733
830
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'twitch' enabled");
@@ -754,7 +851,9 @@ var ManagerUtils = class {
754
851
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'yandexmusic' enabled");
755
852
  }
756
853
  if (SourceLinksRegexes.jiosaavn.test(queryString) && !node.info?.sourceManagers?.includes("jiosaavn")) {
757
- throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled");
854
+ throw new Error(
855
+ "Query / Link Provided for this Source but Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled"
856
+ );
758
857
  }
759
858
  if (SourceLinksRegexes.tidal.test(queryString) && !node.info?.sourceManagers?.includes("tidal")) {
760
859
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'tidal' enabled");
@@ -764,46 +863,112 @@ var ManagerUtils = class {
764
863
  }
765
864
  return;
766
865
  }
767
- transformQuery(query) {
768
- const sourceOfQuery = typeof query === "string" ? void 0 : DefaultSources[query.source?.trim?.()?.toLowerCase?.() ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? query.source?.trim?.()?.toLowerCase?.();
769
- const Query = {
770
- query: typeof query === "string" ? query : query.query,
771
- extraQueryUrlParams: typeof query !== "string" ? query.extraQueryUrlParams : void 0,
772
- source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
773
- };
774
- const foundSource = Object.keys(DefaultSources).find((source) => Query.query?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
866
+ /**
867
+ * Finds the source of a query string by checking if it starts with a valid source prefix defined in the DefaultSources object. If a valid source prefix is found, it returns the corresponding SearchPlatform; otherwise, it returns null. This function is useful for determining the intended search platform for a given query string, allowing for more accurate search results when the user specifies a source (e.g., "ytsearch:Never Gonna Give You Up" would indicate that the search should be performed on YouTube).
868
+ * @param queryString
869
+ * @returns
870
+ */
871
+ findSourceOfQuery(queryString) {
872
+ const foundSource = Object.keys(DefaultSources).find((source) => queryString?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
775
873
  if (foundSource && !["https", "http"].includes(foundSource) && DefaultSources[foundSource]) {
776
- Query.source = DefaultSources[foundSource];
777
- Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length);
874
+ return foundSource;
778
875
  }
779
- return Query;
876
+ return null;
780
877
  }
878
+ /**
879
+ * Extracts the source from the query if it starts with a valid source prefix (e.g., "ytsearch:") and updates the searchQuery object accordingly.
880
+ * @param searchQuery
881
+ * @returns The updated searchQuery object with the extracted source and modified query string.
882
+ */
883
+ extractSourceOfQuery(searchQuery) {
884
+ const foundSource = this.findSourceOfQuery(searchQuery.query);
885
+ if (foundSource) {
886
+ searchQuery.source = DefaultSources[foundSource];
887
+ searchQuery.query = searchQuery.query.slice(`${foundSource}:`.length, searchQuery.query.length);
888
+ }
889
+ return searchQuery;
890
+ }
891
+ /**
892
+ * Converts a string to lowercase if the input is a string, otherwise returns the input as is. This is useful for ensuring that search platform identifiers are case-insensitive while allowing other types of input to pass through unchanged.
893
+ * @param input
894
+ * @returns
895
+ */
896
+ typedLowerCase(input) {
897
+ if (!input) return input;
898
+ if (typeof input === "string") return input.toLowerCase();
899
+ return input;
900
+ }
901
+ /**
902
+ * Transforms a search query by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, and the determined search platform to be used for the search operation.
903
+ * @param query
904
+ * @returns
905
+ */
906
+ transformQuery(query) {
907
+ const typedDefault = this.typedLowerCase(this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform);
908
+ if (typeof query === "string") {
909
+ const Query = {
910
+ query,
911
+ extraQueryUrlParams: void 0,
912
+ source: typedDefault
913
+ };
914
+ return this.extractSourceOfQuery(Query);
915
+ }
916
+ const providedSource = query?.source?.trim?.()?.toLowerCase?.();
917
+ const validSourceExtracted = DefaultSources[providedSource ?? typedDefault];
918
+ return this.extractSourceOfQuery({
919
+ query: query.query,
920
+ extraQueryUrlParams: query.extraQueryUrlParams,
921
+ source: validSourceExtracted ?? providedSource ?? typedDefault
922
+ });
923
+ }
924
+ /**
925
+ * Transforms a LavaSearchQuery by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, the determined search platform to be used for the search operation, and the types of search (track, playlist, artist, album, text) to be performed.
926
+ * @param query
927
+ * @returns
928
+ */
781
929
  transformLavaSearchQuery(query) {
782
- const sourceOfQuery = typeof query === "string" ? void 0 : DefaultSources[query.source?.trim?.()?.toLowerCase?.() ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? query.source?.trim?.()?.toLowerCase?.();
930
+ const typedDefault = this.typedLowerCase(this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform);
931
+ if (typeof query === "string") {
932
+ const Query2 = {
933
+ query,
934
+ types: [],
935
+ extraQueryUrlParams: void 0,
936
+ source: typedDefault
937
+ };
938
+ return this.extractSourceOfQuery(Query2);
939
+ }
940
+ const providedSource = query?.source?.trim?.()?.toLowerCase?.();
941
+ const validSourceExtracted = DefaultSources[providedSource ?? typedDefault];
783
942
  const Query = {
784
- query: typeof query === "string" ? query : query.query,
785
- types: query.types ? ["track", "playlist", "artist", "album", "text"].filter((v) => query.types?.find((x) => x.toLowerCase().startsWith(v))) : [
943
+ query: query.query,
944
+ types: query.types ? ["track", "playlist", "artist", "album", "text"].filter(
945
+ (v) => query.types?.find((x) => x.toLowerCase().startsWith(v))
946
+ ) : [
786
947
  "track",
787
948
  "playlist",
788
949
  "artist",
789
950
  "album"
790
951
  /*"text"*/
791
952
  ],
792
- source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
953
+ source: validSourceExtracted ?? providedSource ?? typedDefault
793
954
  };
794
- const foundSource = Object.keys(DefaultSources).find((source) => Query.query.toLowerCase().startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
795
- if (foundSource && DefaultSources[foundSource]) {
796
- Query.source = DefaultSources[foundSource];
797
- Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length);
798
- }
799
- return Query;
955
+ return this.extractSourceOfQuery(Query);
800
956
  }
957
+ /**
958
+ * Validates the provided source string against the capabilities of the Lavalink node. It checks if the source string is supported by the node's enabled source managers and plugins, throwing errors if any required sources or plugins are missing for the specified search platform. This ensures that search queries are only executed with compatible sources based on the node's configuration.
959
+ * @param node
960
+ * @param sourceString
961
+ * @returns
962
+ */
801
963
  validateSourceString(node, sourceString) {
802
964
  if (!sourceString) throw new Error(`No SourceString was provided`);
803
965
  const source = DefaultSources[sourceString.toLowerCase().trim()];
804
- if (!source) throw new Error(`Lavalink Node SearchQuerySource: '${sourceString}' is not available`);
966
+ if (!source && !!this.LavalinkManager.options.playerOptions.allowCustomSources)
967
+ throw new Error(
968
+ `Lavalink-Client does not support SearchQuerySource: '${sourceString}'. You can disable this check by setting 'ManagerOptions.PlayerOptions.allowCustomSources' to true`
969
+ );
805
970
  if (!node.info) throw new Error("Lavalink Node does not have any info cached yet, not ready yet!");
806
- if (!this.LavalinkManager.options?.autoChecks?.sourcesValidations) return;
971
+ if (!node._checkForSources) return;
807
972
  if (source === "amsearch" && !node.info?.sourceManagers?.includes("applemusic")) {
808
973
  throw new Error("Lavalink Node has not 'applemusic' enabled, which is required to have 'amsearch' work");
809
974
  }
@@ -817,15 +982,21 @@ var ManagerUtils = class {
817
982
  throw new Error("Lavalink Node has not 'http' enabled, which is required to have 'dzisrc' to work");
818
983
  }
819
984
  if (source === "jsrec" && !node.info?.sourceManagers?.includes("jiosaavn")) {
820
- throw new Error("Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled, which is required to have 'jsrec' to work");
985
+ throw new Error(
986
+ "Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled, which is required to have 'jsrec' to work"
987
+ );
821
988
  }
822
989
  if (source === "jssearch" && !node.info?.sourceManagers?.includes("jiosaavn")) {
823
- throw new Error("Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled, which is required to have 'jssearch' to work");
990
+ throw new Error(
991
+ "Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled, which is required to have 'jssearch' to work"
992
+ );
824
993
  }
825
994
  if (source === "scsearch" && !node.info?.sourceManagers?.includes("soundcloud")) {
826
995
  throw new Error("Lavalink Node has not 'soundcloud' enabled, which is required to have 'scsearch' work");
827
996
  }
828
- if (source === "speak" && this.LavalinkManager.options?.autoChecks?.pluginValidations && !node.info?.plugins?.find((c) => c.name.toLowerCase().includes(LavalinkPlugins.DuncteBot_Plugin.toLowerCase()))) {
997
+ if (source === "speak" && node._checkForPlugins && !node.info?.plugins?.find(
998
+ (c) => c.name.toLowerCase().includes(LavalinkPlugins.DuncteBot_Plugin.toLowerCase())
999
+ )) {
829
1000
  throw new Error("Lavalink Node has not 'speak' enabled, which is required to have 'speak' work");
830
1001
  }
831
1002
  if (source === "tdsearch" && !node.info?.sourceManagers?.includes("tidal")) {
@@ -834,7 +1005,9 @@ var ManagerUtils = class {
834
1005
  if (source === "tdrec" && !node.info?.sourceManagers?.includes("tidal")) {
835
1006
  throw new Error("Lavalink Node has not 'tidal' enabled, which is required to have 'tdrec' work");
836
1007
  }
837
- if (source === "tts" && this.LavalinkManager.options?.autoChecks?.pluginValidations && !node.info?.plugins?.find((c) => c.name.toLowerCase().includes(LavalinkPlugins.GoogleCloudTTS.toLowerCase()))) {
1008
+ if (source === "tts" && node._checkForPlugins && !node.info?.plugins?.find(
1009
+ (c) => c.name.toLowerCase().includes(LavalinkPlugins.GoogleCloudTTS.toLowerCase())
1010
+ )) {
838
1011
  throw new Error("Lavalink Node has not 'tts' enabled, which is required to have 'tts' work");
839
1012
  }
840
1013
  if (source === "ftts" && !(node.info?.sourceManagers?.includes("ftts") || node.info?.sourceManagers?.includes("flowery-tts") || node.info?.sourceManagers?.includes("flowerytts"))) {
@@ -897,13 +1070,15 @@ var MiniMap = class extends Map {
897
1070
  async function queueTrackEnd(player, dontShiftQueue = false) {
898
1071
  if (player.queue.current && !player.queue.current?.pluginInfo?.clientData?.previousTrack) {
899
1072
  player.queue.previous.unshift(player.queue.current);
900
- if (player.queue.previous.length > player.queue.options.maxPreviousTracks) player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
1073
+ if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
1074
+ player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
901
1075
  await player.queue.utils.save();
902
1076
  }
903
1077
  if (player.repeatMode === "queue" && player.queue.current) player.queue.tracks.push(player.queue.current);
904
1078
  const nextSong = dontShiftQueue ? null : player.queue.tracks.shift();
905
1079
  try {
906
- if (nextSong && player.LavalinkManager.utils.isUnresolvedTrack(nextSong)) await nextSong.resolve(player);
1080
+ if (nextSong && player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
1081
+ await nextSong.resolve(player);
907
1082
  player.queue.current = nextSong || null;
908
1083
  await player.queue.utils.save();
909
1084
  } catch (error) {
@@ -916,7 +1091,8 @@ async function queueTrackEnd(player, dontShiftQueue = false) {
916
1091
  });
917
1092
  }
918
1093
  player.LavalinkManager.emit("trackError", player, player.queue.current, error);
919
- if (!dontShiftQueue && player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0]) return queueTrackEnd(player);
1094
+ if (!dontShiftQueue && player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
1095
+ return queueTrackEnd(player);
920
1096
  }
921
1097
  return player.queue.current;
922
1098
  }
@@ -928,18 +1104,23 @@ async function applyUnresolvedData(resTrack, data, utils) {
928
1104
  if (data.info.title?.length) resTrack.info.title = data.info.title;
929
1105
  if (data.info.author?.length) resTrack.info.author = data.info.author;
930
1106
  } else {
931
- if ((resTrack.info.title === "Unknown title" || resTrack.info.title === "Unspecified description") && resTrack.info.title != data.info.title) resTrack.info.title = data.info.title;
1107
+ if ((resTrack.info.title === "Unknown title" || resTrack.info.title === "Unspecified description") && resTrack.info.title != data.info.title)
1108
+ resTrack.info.title = data.info.title;
932
1109
  if (resTrack.info.author !== data.info.author) resTrack.info.author = data.info.author;
933
1110
  if (resTrack.info.artworkUrl !== data.info.artworkUrl) resTrack.info.artworkUrl = data.info.artworkUrl;
934
1111
  }
935
- for (const key of Object.keys(data.info)) if (typeof resTrack.info[key] === "undefined" && key !== "resolve" && data.info[key]) resTrack.info[key] = data.info[key];
1112
+ for (const key of Object.keys(data.info))
1113
+ if (typeof resTrack.info[key] === "undefined" && key !== "resolve" && data.info[key])
1114
+ resTrack.info[key] = data.info[key];
936
1115
  return resTrack;
937
1116
  }
938
1117
  async function getClosestTrack(data, player) {
939
1118
  if (!player || !player.node) throw new RangeError("No player with a lavalink node was provided");
940
- if (player.LavalinkManager.utils.isTrack(data)) return player.LavalinkManager.utils.buildTrack(data, data.requester);
1119
+ if (player.LavalinkManager.utils.isTrack(data))
1120
+ return player.LavalinkManager.utils.buildTrack(data, data.requester);
941
1121
  if (!player.LavalinkManager.utils.isUnresolvedTrack(data)) throw new RangeError("Track is not an unresolved Track");
942
- if (!data?.info?.title && typeof data.encoded !== "string" && !data.info.uri) throw new SyntaxError("the track uri / title / encoded Base64 string is required for unresolved tracks");
1122
+ if (!data?.info?.title && typeof data.encoded !== "string" && !data.info.uri)
1123
+ throw new SyntaxError("the track uri / title / encoded Base64 string is required for unresolved tracks");
943
1124
  if (!data.requester) throw new SyntaxError("The requester is required");
944
1125
  if (typeof data.encoded === "string") {
945
1126
  const r = await player.node.decode.singleTrack(data.encoded, data.requester);
@@ -951,44 +1132,60 @@ async function getClosestTrack(data, player) {
951
1132
  }
952
1133
  const query = [data.info?.title, data.info?.author].filter((str) => !!str).join(" by ");
953
1134
  const sourceName = data.info?.sourceName;
954
- return await player.search({
955
- query,
956
- source: sourceName !== "twitch" && sourceName !== "flowery-tts" ? sourceName : player.LavalinkManager.options?.playerOptions?.defaultSearchPlatform
957
- }, data.requester).then((res) => {
1135
+ return await player.search(
1136
+ {
1137
+ query,
1138
+ source: sourceName !== "twitch" && sourceName !== "flowery-tts" ? sourceName : player.LavalinkManager.options?.playerOptions?.defaultSearchPlatform
1139
+ },
1140
+ data.requester
1141
+ ).then((res) => {
958
1142
  let trackToUse = null;
959
- if ((data.info?.title || data.info?.author) && !trackToUse) trackToUse = res.tracks.find(
960
- (track) => (
961
- // find via author name (i ... case insensitve)
962
- [data.info?.author || "", `${data.info?.author} - Topic`].some((name) => new RegExp(`^${escapeRegExp(name)}$`, "i").test(track.info?.author)) || // find via title (i ... case insensitve)
963
- new RegExp(`^${escapeRegExp(data.info?.title)}$`, "i").test(track.info?.title)
964
- )
965
- );
966
- if (data.info?.isrc && !trackToUse) trackToUse = res.tracks.find((track) => track.info?.isrc === data.info?.isrc);
967
- if (data.info?.duration && !trackToUse) trackToUse = res.tracks.find((track) => track.info?.duration >= data.info?.duration - 1500 && track?.info.duration <= data.info?.duration + 1500);
1143
+ if ((data.info?.title || data.info?.author) && !trackToUse)
1144
+ trackToUse = res.tracks.find(
1145
+ (track) => (
1146
+ // find via author name (i ... case insensitve)
1147
+ [data.info?.author || "", `${data.info?.author} - Topic`].some(
1148
+ (name) => new RegExp(`^${escapeRegExp(name)}$`, "i").test(track.info?.author)
1149
+ ) || // find via title (i ... case insensitve)
1150
+ new RegExp(`^${escapeRegExp(data.info?.title)}$`, "i").test(track.info?.title)
1151
+ )
1152
+ );
1153
+ if (data.info?.isrc && !trackToUse)
1154
+ trackToUse = res.tracks.find((track) => track.info?.isrc === data.info?.isrc);
1155
+ if (data.info?.duration && !trackToUse)
1156
+ trackToUse = res.tracks.find(
1157
+ (track) => track.info?.duration >= data.info?.duration - 1500 && track?.info.duration <= data.info?.duration + 1500
1158
+ );
968
1159
  return applyUnresolvedData(trackToUse || res.tracks[0], data, player.LavalinkManager.utils);
969
1160
  });
970
1161
  }
971
1162
  function safeStringify(obj, padding = 0) {
972
1163
  const seen = /* @__PURE__ */ new WeakSet();
973
- return JSON.stringify(obj, (key, value) => {
974
- if (typeof value === "function") return void 0;
975
- if (typeof value === "symbol") return void 0;
976
- if (typeof value === "bigint") return value.toString();
977
- if (typeof value === "object" && value !== null) {
978
- if (seen.has(value)) return "[Circular]";
979
- seen.add(value);
980
- }
981
- return value;
982
- }, padding);
1164
+ return JSON.stringify(
1165
+ obj,
1166
+ (key, value) => {
1167
+ if (typeof value === "function") return void 0;
1168
+ if (typeof value === "symbol") return void 0;
1169
+ if (typeof value === "bigint") return value.toString();
1170
+ if (typeof value === "object" && value !== null) {
1171
+ if (seen.has(value)) return "[Circular]";
1172
+ seen.add(value);
1173
+ }
1174
+ return value;
1175
+ },
1176
+ padding
1177
+ );
983
1178
  }
984
1179
 
985
1180
  // src/structures/Node.ts
986
- var LavalinkNode = class {
1181
+ var LavalinkNode = class _LavalinkNode {
987
1182
  heartBeatPingTimestamp = 0;
988
1183
  heartBeatPongTimestamp = 0;
989
1184
  heartBeatInterval;
990
1185
  pingTimeout;
1186
+ nodeType = "Lavalink";
991
1187
  isAlive = false;
1188
+ static _NodeLinkClass = null;
992
1189
  /** The provided Options of the Node */
993
1190
  options;
994
1191
  /** The amount of rest calls the node has made. */
@@ -1028,7 +1225,7 @@ var LavalinkNode = class {
1028
1225
  };
1029
1226
  /** The current sessionId, only present when connected */
1030
1227
  sessionId = null;
1031
- /** Whether the node resuming is enabled or not */
1228
+ /** Wether the node resuming is enabled or not */
1032
1229
  resuming = { enabled: true, timeout: null };
1033
1230
  /** Actual Lavalink Information of the Node */
1034
1231
  info = null;
@@ -1057,16 +1254,17 @@ var LavalinkNode = class {
1057
1254
  return this.heartBeatPongTimestamp - this.heartBeatPingTimestamp;
1058
1255
  }
1059
1256
  /**
1060
- * Returns whether the plugin validations are enabled or not
1257
+ * Returns wether the plugin validations are enabled or not
1061
1258
  */
1062
1259
  get _checkForPlugins() {
1063
- return !!this._LManager.options?.autoChecks?.pluginValidations;
1260
+ if (this.nodeType === "NodeLink") return false;
1261
+ return !!this.options?.autoChecks?.pluginValidations;
1064
1262
  }
1065
1263
  /**
1066
- * Returns whether the source validations are enabled or not
1264
+ * Returns wether the source validations are enabled or not
1067
1265
  */
1068
1266
  get _checkForSources() {
1069
- return !!this._LManager.options?.autoChecks?.sourcesValidations;
1267
+ return !!this.options?.autoChecks?.sourcesValidations;
1070
1268
  }
1071
1269
  /**
1072
1270
  * Emits a debug event to the LavalinkManager
@@ -1127,13 +1325,22 @@ var LavalinkNode = class {
1127
1325
  retryTimespan: -1,
1128
1326
  requestSignalTimeoutMS: 1e4,
1129
1327
  heartBeatInterval: 3e4,
1130
- closeOnError: true,
1131
1328
  enablePingOnStatsCheck: true,
1132
- ...options
1329
+ closeOnError: true,
1330
+ ...options,
1331
+ autoChecks: {
1332
+ sourcesValidations: options?.autoChecks?.sourcesValidations ?? true,
1333
+ pluginValidations: options?.autoChecks?.pluginValidations ?? true
1334
+ }
1133
1335
  };
1336
+ if (this.options.nodeType === "NodeLink" && this.constructor.name === "LavalinkNode" && _LavalinkNode._NodeLinkClass) {
1337
+ return new _LavalinkNode._NodeLinkClass(options, manager);
1338
+ }
1339
+ this.nodeType = this.options.nodeType || "Lavalink";
1134
1340
  this.NodeManager = manager;
1135
1341
  this.validate();
1136
- if (this.options.secure && this.options.port !== 443) throw new SyntaxError("If secure is true, then the port must be 443");
1342
+ if (this.options.secure && this.options.port !== 443)
1343
+ throw new SyntaxError("If secure is true, then the port must be 443");
1137
1344
  this.options.regions = (this.options.regions || []).map((a) => a.toLowerCase());
1138
1345
  Object.defineProperty(this, NodeSymbol, { configurable: true, value: true });
1139
1346
  }
@@ -1154,7 +1361,7 @@ var LavalinkNode = class {
1154
1361
  path: `/${this.version}/${endpoint.startsWith("/") ? endpoint.slice(1) : endpoint}`,
1155
1362
  method: "GET",
1156
1363
  headers: {
1157
- "Authorization": this.options.authorization
1364
+ Authorization: this.options.authorization
1158
1365
  },
1159
1366
  signal: this.options.requestSignalTimeoutMS && this.options.requestSignalTimeoutMS > 0 ? AbortSignal.timeout(this.options.requestSignalTimeoutMS) : void 0
1160
1367
  };
@@ -1173,18 +1380,22 @@ var LavalinkNode = class {
1173
1380
  return { response, options };
1174
1381
  }
1175
1382
  async request(endpoint, modify, parseAsText) {
1176
- if (!this.connected) throw new Error("The node is not connected to the Lavalink Server!, Please call node.connect() first!");
1383
+ if (!this.connected)
1384
+ throw new Error("The node is not connected to the Lavalink Server!, Please call node.connect() first!");
1177
1385
  const { response, options } = await this.rawRequest(endpoint, modify);
1178
1386
  if (["DELETE", "PUT"].includes(options.method)) return;
1179
1387
  if (response.status === 204) return;
1180
- if (response.status === 404) throw new Error(`Node Request resulted into an error, request-PATH: ${options.path} | headers: ${safeStringify(response.headers)}`);
1388
+ if (response.status === 404)
1389
+ throw new Error(
1390
+ `Node Request resulted into an error, request-PATH: ${options.path} | headers: ${safeStringify(response.headers)}`
1391
+ );
1181
1392
  return parseAsText ? await response.text() : await response.json();
1182
1393
  }
1183
1394
  /**
1184
1395
  * Search something raw on the node, please note only add tracks to players of that node
1185
1396
  * @param query SearchQuery Object
1186
1397
  * @param requestUser Request User for creating the player(s)
1187
- * @param throwOnEmpty Whether to throw on an empty result or not
1398
+ * @param throwOnEmpty Wether to throw on an empty result or not
1188
1399
  * @returns Searchresult
1189
1400
  *
1190
1401
  * @example
@@ -1198,7 +1409,7 @@ var LavalinkNode = class {
1198
1409
  const Query = this._LManager.utils.transformQuery(query);
1199
1410
  this._LManager.utils.validateQueryString(this, Query.query, Query.source);
1200
1411
  if (Query.source) this._LManager.utils.validateSourceString(this, Query.source);
1201
- if (["bcsearch", "bandcamp"].includes(Query.source) && this._LManager.options?.autoChecks?.sourcesValidations && !this.info.sourceManagers.includes("bandcamp")) {
1412
+ if (["bcsearch", "bandcamp"].includes(Query.source) && this._checkForSources && !this.info.sourceManagers.includes("bandcamp")) {
1202
1413
  throw new Error("Bandcamp Search only works on the player (lavaplayer version < 2.2.0!");
1203
1414
  }
1204
1415
  const requestUrl = new URL(`${this.restAddress}/loadtracks`);
@@ -1234,8 +1445,14 @@ var LavalinkNode = class {
1234
1445
  author: res.data.info?.author || res.data.pluginInfo?.author || null,
1235
1446
  thumbnail: res.data.info?.artworkUrl || res.data.pluginInfo?.artworkUrl || (typeof res.data?.info?.selectedTrack !== "number" || res.data?.info?.selectedTrack === -1 ? null : resTracks[res.data?.info?.selectedTrack] ? resTracks[res.data?.info?.selectedTrack]?.info?.artworkUrl || resTracks[res.data?.info?.selectedTrack]?.info?.pluginInfo?.artworkUrl : null) || null,
1236
1447
  uri: res.data.info?.url || res.data.info?.uri || res.data.info?.link || res.data.pluginInfo?.url || res.data.pluginInfo?.uri || res.data.pluginInfo?.link || null,
1237
- selectedTrack: typeof res.data?.info?.selectedTrack !== "number" || res.data?.info?.selectedTrack === -1 ? null : resTracks[res.data?.info?.selectedTrack] ? this._LManager.utils.buildTrack(resTracks[res.data?.info?.selectedTrack], requestUser) : null,
1238
- duration: resTracks.length ? resTracks.reduce((acc, cur) => acc + (cur?.info?.duration || cur?.info?.length || 0), 0) : 0
1448
+ selectedTrack: typeof res.data?.info?.selectedTrack !== "number" || res.data?.info?.selectedTrack === -1 ? null : resTracks[res.data?.info?.selectedTrack] ? this._LManager.utils.buildTrack(
1449
+ resTracks[res.data?.info?.selectedTrack],
1450
+ requestUser
1451
+ ) : null,
1452
+ duration: resTracks.length ? resTracks.reduce(
1453
+ (acc, cur) => acc + (cur?.info?.duration || cur?.info?.length || 0),
1454
+ 0
1455
+ ) : 0
1239
1456
  } : null,
1240
1457
  tracks: resTracks.length ? resTracks.map((t) => this._LManager.utils.buildTrack(t, requestUser)) : []
1241
1458
  };
@@ -1244,7 +1461,7 @@ var LavalinkNode = class {
1244
1461
  * Search something using the lavaSearchPlugin (filtered searches by types)
1245
1462
  * @param query LavaSearchQuery Object
1246
1463
  * @param requestUser Request User for creating the player(s)
1247
- * @param throwOnEmpty Whether to throw on an empty result or not
1464
+ * @param throwOnEmpty Wether to throw on an empty result or not
1248
1465
  * @returns LavaSearchresult (SearchResult if link is provided)
1249
1466
  *
1250
1467
  * @example
@@ -1256,11 +1473,19 @@ var LavalinkNode = class {
1256
1473
  async lavaSearch(query, requestUser, throwOnEmpty = false) {
1257
1474
  const Query = this._LManager.utils.transformLavaSearchQuery(query);
1258
1475
  if (Query.source) this._LManager.utils.validateSourceString(this, Query.source);
1259
- if (/^https?:\/\//.test(Query.query)) return this.search({ query: Query.query, source: Query.source }, requestUser);
1260
- if (!["spsearch", "sprec", "amsearch", "dzsearch", "dzisrc", "ytmsearch", "ytsearch"].includes(Query.source)) throw new SyntaxError(`Query.source must be a source from LavaSrc: "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "ytmsearch" | "ytsearch"`);
1261
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasearch-plugin")) throw new RangeError(`there is no lavasearch-plugin available in the lavalink node: ${this.id}`);
1262
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasrc-plugin")) throw new RangeError(`there is no lavasrc-plugin available in the lavalink node: ${this.id}`);
1263
- const { response } = await this.rawRequest(`/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`);
1476
+ if (/^https?:\/\//.test(Query.query))
1477
+ return this.search({ query: Query.query, source: Query.source }, requestUser);
1478
+ if (!["spsearch", "sprec", "amsearch", "dzsearch", "dzisrc", "ytmsearch", "ytsearch"].includes(Query.source))
1479
+ throw new SyntaxError(
1480
+ `Query.source must be a source from LavaSrc: "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "ytmsearch" | "ytsearch"`
1481
+ );
1482
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasearch-plugin"))
1483
+ throw new RangeError(`there is no lavasearch-plugin available in the lavalink node: ${this.id}`);
1484
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasrc-plugin"))
1485
+ throw new RangeError(`there is no lavasrc-plugin available in the lavalink node: ${this.id}`);
1486
+ const { response } = await this.rawRequest(
1487
+ `/loadsearch?query=${Query.source ? `${Query.source}:` : ""}${encodeURIComponent(Query.query)}${Query.types?.length ? `&types=${Query.types.join(",")}` : ""}`
1488
+ );
1264
1489
  const res = response.status === 204 ? {} : await response.json();
1265
1490
  if (throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length) {
1266
1491
  this._emitDebugEvent("LavaSearchNothingFound" /* LavaSearchNothingFound */, {
@@ -1272,10 +1497,25 @@ var LavalinkNode = class {
1272
1497
  }
1273
1498
  return {
1274
1499
  tracks: res.tracks?.map((v) => this._LManager.utils.buildTrack(v, requestUser)) || [],
1275
- albums: res.albums?.map((v) => ({ info: v.info, pluginInfo: v?.plugin || v.pluginInfo, tracks: v.tracks.map((v2) => this._LManager.utils.buildTrack(v2, requestUser)) })) || [],
1276
- artists: res.artists?.map((v) => ({ info: v.info, pluginInfo: v?.plugin || v.pluginInfo, tracks: v.tracks.map((v2) => this._LManager.utils.buildTrack(v2, requestUser)) })) || [],
1277
- playlists: res.playlists?.map((v) => ({ info: v.info, pluginInfo: v?.plugin || v.pluginInfo, tracks: v.tracks.map((v2) => this._LManager.utils.buildTrack(v2, requestUser)) })) || [],
1278
- texts: res.texts?.map((v) => ({ text: v.text, pluginInfo: v?.plugin || v.pluginInfo })) || [],
1500
+ albums: res.albums?.map((v) => ({
1501
+ info: v.info,
1502
+ pluginInfo: v?.plugin || v.pluginInfo,
1503
+ tracks: v.tracks.map((v2) => this._LManager.utils.buildTrack(v2, requestUser))
1504
+ })) || [],
1505
+ artists: res.artists?.map((v) => ({
1506
+ info: v.info,
1507
+ pluginInfo: v?.plugin || v.pluginInfo,
1508
+ tracks: v.tracks.map((v2) => this._LManager.utils.buildTrack(v2, requestUser))
1509
+ })) || [],
1510
+ playlists: res.playlists?.map((v) => ({
1511
+ info: v.info,
1512
+ pluginInfo: v?.plugin || v.pluginInfo,
1513
+ tracks: v.tracks.map((v2) => this._LManager.utils.buildTrack(v2, requestUser))
1514
+ })) || [],
1515
+ texts: res.texts?.map((v) => ({
1516
+ text: v.text,
1517
+ pluginInfo: v?.plugin || v.pluginInfo
1518
+ })) || [],
1279
1519
  pluginInfo: res.pluginInfo || res?.plugin
1280
1520
  };
1281
1521
  }
@@ -1299,7 +1539,10 @@ var LavalinkNode = class {
1299
1539
  r.body = safeStringify(data.playerOptions);
1300
1540
  if (data.noReplace) {
1301
1541
  const url = new URL(`${this.restAddress}${r.path}`);
1302
- url.searchParams.append("noReplace", data.noReplace === true && typeof data.noReplace === "boolean" ? "true" : "false");
1542
+ url.searchParams.append(
1543
+ "noReplace",
1544
+ data.noReplace === true && typeof data.noReplace === "boolean" ? "true" : "false"
1545
+ );
1303
1546
  r.path = url.pathname + url.search;
1304
1547
  }
1305
1548
  });
@@ -1353,19 +1596,26 @@ var LavalinkNode = class {
1353
1596
  const headers = {
1354
1597
  Authorization: this.options.authorization,
1355
1598
  "User-Id": this._LManager.options.client.id,
1356
- "Client-Name": this._LManager.options.client.username || "Lavalink-Client"
1599
+ "Client-Name": String(this._LManager.options.client.username || "Lavalink-Client").replace(
1600
+ /[^\x20-\x7E]/g,
1601
+ ""
1602
+ )
1357
1603
  };
1358
1604
  if (typeof this.options.sessionId === "string" || typeof sessionId === "string") {
1359
1605
  headers["Session-Id"] = this.options.sessionId || sessionId;
1360
1606
  this.sessionId = this.options.sessionId || sessionId;
1361
1607
  }
1362
- this.socket = new WebSocket(`ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`, { headers });
1608
+ this.socket = new WebSocket(
1609
+ `ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`,
1610
+ { headers }
1611
+ );
1363
1612
  this.socket.on("open", this.open.bind(this));
1364
1613
  this.socket.on("close", (code, reason) => this.close(code, reason?.toString()));
1365
1614
  this.socket.on("message", this.message.bind(this));
1366
1615
  this.socket.on("error", this.error.bind(this));
1367
1616
  }
1368
1617
  heartBeat() {
1618
+ if (this.nodeType !== "Lavalink") return;
1369
1619
  this._emitDebugEvent("HeartBeatTriggered" /* HeartBeatTriggered */, {
1370
1620
  state: "log",
1371
1621
  message: `Node Socket Heartbeat triggered, resetting old Timeout to 65000ms (should happen every 60s due to /stats event)`,
@@ -1405,7 +1655,7 @@ var LavalinkNode = class {
1405
1655
  /**
1406
1656
  * Destroys the Node-Connection (Websocket) and all player's of the node
1407
1657
  * @param destroyReason Destroy Reason to use when destroying the players
1408
- * @param deleteNode whether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
1658
+ * @param deleteNode wether to delete the nodte from the nodes list too, if false it will emit a disconnect. @default true
1409
1659
  * @param movePlayers whether to movePlayers to different eligible connected node. If false players won't be moved @default false
1410
1660
  * @returns void
1411
1661
  *
@@ -1427,8 +1677,11 @@ var LavalinkNode = class {
1427
1677
  this.socket?.removeAllListeners();
1428
1678
  this.socket = null;
1429
1679
  this.resetReconnectionAttempts();
1430
- if (!deleteNode) return void this.NodeManager.emit("disconnect", this, { code: 1e3, reason: destroyReason });
1431
- ;
1680
+ if (!deleteNode)
1681
+ return void this.NodeManager.emit("disconnect", this, {
1682
+ code: 1e3,
1683
+ reason: destroyReason
1684
+ });
1432
1685
  this.NodeManager.emit("destroy", this, destroyReason);
1433
1686
  this.NodeManager.nodes.delete(this.id);
1434
1687
  this.resetAckTimeouts(true, true);
@@ -1436,55 +1689,67 @@ var LavalinkNode = class {
1436
1689
  }
1437
1690
  const handlePlayerOperations = () => {
1438
1691
  if (!movePlayers) {
1439
- return Promise.allSettled(Array.from(players.values()).map(
1440
- (player) => player.destroy(destroyReason || "NodeDestroy" /* NodeDestroy */).catch((error) => {
1441
- this._emitDebugEvent("PlayerDestroyFail" /* PlayerDestroyFail */, {
1442
- state: "error",
1443
- message: `Failed to destroy player ${player.guildId}: ${error.message}`,
1444
- error,
1445
- functionLayer: "Node > destroy() > movePlayers"
1446
- });
1447
- })
1448
- ));
1692
+ return Promise.allSettled(
1693
+ Array.from(players.values()).map(
1694
+ (player) => player.destroy(destroyReason || "NodeDestroy" /* NodeDestroy */).catch((error) => {
1695
+ this._emitDebugEvent("PlayerDestroyFail" /* PlayerDestroyFail */, {
1696
+ state: "error",
1697
+ message: `Failed to destroy player ${player.guildId}: ${error.message}`,
1698
+ error,
1699
+ functionLayer: "Node > destroy() > movePlayers"
1700
+ });
1701
+ })
1702
+ )
1703
+ );
1449
1704
  }
1450
- const nodeToMove = Array.from(this.NodeManager.leastUsedNodes("playingPlayers")).find((n) => n.connected && n.options.id !== this.id);
1705
+ const nodeToMove = Array.from(this.NodeManager.leastUsedNodes("playingPlayers")).find(
1706
+ (n) => n.connected && n.options.id !== this.id
1707
+ );
1451
1708
  if (!nodeToMove) {
1452
- return Promise.allSettled(Array.from(players.values()).map(
1453
- (player) => player.destroy("PlayerChangeNodeFailNoEligibleNode" /* PlayerChangeNodeFailNoEligibleNode */).catch((error) => {
1454
- this._emitDebugEvent("PlayerChangeNodeFailNoEligibleNode" /* PlayerChangeNodeFailNoEligibleNode */, {
1709
+ return Promise.allSettled(
1710
+ Array.from(players.values()).map(
1711
+ (player) => player.destroy("PlayerChangeNodeFailNoEligibleNode" /* PlayerChangeNodeFailNoEligibleNode */).catch((error) => {
1712
+ this._emitDebugEvent("PlayerChangeNodeFailNoEligibleNode" /* PlayerChangeNodeFailNoEligibleNode */, {
1713
+ state: "error",
1714
+ message: `Failed to destroy player ${player.guildId}: ${error.message}`,
1715
+ error,
1716
+ functionLayer: "Node > destroy() > movePlayers"
1717
+ });
1718
+ })
1719
+ )
1720
+ );
1721
+ }
1722
+ return Promise.allSettled(
1723
+ Array.from(players.values()).map(
1724
+ (player) => player.changeNode(nodeToMove.options.id).catch((error) => {
1725
+ this._emitDebugEvent("PlayerChangeNodeFail" /* PlayerChangeNodeFail */, {
1455
1726
  state: "error",
1456
- message: `Failed to destroy player ${player.guildId}: ${error.message}`,
1727
+ message: `Failed to move player ${player.guildId}: ${error.message}`,
1457
1728
  error,
1458
1729
  functionLayer: "Node > destroy() > movePlayers"
1459
1730
  });
1460
- })
1461
- ));
1462
- }
1463
- return Promise.allSettled(Array.from(players.values()).map(
1464
- (player) => player.changeNode(nodeToMove.options.id).catch((error) => {
1465
- this._emitDebugEvent("PlayerChangeNodeFail" /* PlayerChangeNodeFail */, {
1466
- state: "error",
1467
- message: `Failed to move player ${player.guildId}: ${error.message}`,
1468
- error,
1469
- functionLayer: "Node > destroy() > movePlayers"
1470
- });
1471
- return player.destroy(error.message ?? "PlayerChangeNodeFail" /* PlayerChangeNodeFail */).catch((destroyError) => {
1472
- this._emitDebugEvent("PlayerDestroyFail" /* PlayerDestroyFail */, {
1473
- state: "error",
1474
- message: `Failed to destroy player ${player.guildId} after move failure: ${destroyError.message}`,
1475
- error: destroyError,
1476
- functionLayer: "Node > destroy() > movePlayers"
1731
+ return player.destroy(error.message ?? "PlayerChangeNodeFail" /* PlayerChangeNodeFail */).catch((destroyError) => {
1732
+ this._emitDebugEvent("PlayerDestroyFail" /* PlayerDestroyFail */, {
1733
+ state: "error",
1734
+ message: `Failed to destroy player ${player.guildId} after move failure: ${destroyError.message}`,
1735
+ error: destroyError,
1736
+ functionLayer: "Node > destroy() > movePlayers"
1737
+ });
1477
1738
  });
1478
- });
1479
- })
1480
- ));
1739
+ })
1740
+ )
1741
+ );
1481
1742
  };
1482
1743
  return void handlePlayerOperations().finally(() => {
1483
1744
  this.socket?.close(1e3, "Node-Destroy");
1484
1745
  this.socket?.removeAllListeners();
1485
1746
  this.socket = null;
1486
1747
  this.resetReconnectionAttempts();
1487
- if (!deleteNode) return void this.NodeManager.emit("disconnect", this, { code: 1e3, reason: destroyReason });
1748
+ if (!deleteNode)
1749
+ return void this.NodeManager.emit("disconnect", this, {
1750
+ code: 1e3,
1751
+ reason: destroyReason
1752
+ });
1488
1753
  this.NodeManager.emit("destroy", this, destroyReason);
1489
1754
  this.NodeManager.nodes.delete(this.id);
1490
1755
  this.resetAckTimeouts(true, true);
@@ -1585,7 +1850,12 @@ var LavalinkNode = class {
1585
1850
  */
1586
1851
  singleTrack: async (encoded, requester) => {
1587
1852
  if (!encoded) throw new SyntaxError("No encoded (Base64 string) was provided");
1588
- return this._LManager.utils?.buildTrack(await this.request(`/decodetrack?encodedTrack=${encodeURIComponent(encoded.replace(/\s/g, ""))}`), requester);
1853
+ return this._LManager.utils?.buildTrack(
1854
+ await this.request(
1855
+ `/decodetrack?encodedTrack=${encodeURIComponent(encoded.replace(/\s/g, ""))}`
1856
+ ),
1857
+ requester
1858
+ );
1589
1859
  },
1590
1860
  /**
1591
1861
  * Decodes multiple tracks into their info
@@ -1601,7 +1871,8 @@ var LavalinkNode = class {
1601
1871
  * ```
1602
1872
  */
1603
1873
  multipleTracks: async (encodeds, requester) => {
1604
- if (!Array.isArray(encodeds) || !encodeds.every((v) => typeof v === "string" && v.length > 1)) throw new SyntaxError("You need to provide encodeds, which is an array of base64 strings");
1874
+ if (!Array.isArray(encodeds) || !encodeds.every((v) => typeof v === "string" && v.length > 1))
1875
+ throw new SyntaxError("You need to provide encodeds, which is an array of base64 strings");
1605
1876
  return await this.request(`/decodetracks`, (r) => {
1606
1877
  r.method = "POST";
1607
1878
  r.body = safeStringify(encodeds);
@@ -1613,7 +1884,7 @@ var LavalinkNode = class {
1613
1884
  /**
1614
1885
  * Get the lyrics of a track
1615
1886
  * @param track the track to get the lyrics for
1616
- * @param skipTrackSource whether to skip the track source or not
1887
+ * @param skipTrackSource wether to skip the track source or not
1617
1888
  * @returns the lyrics of the track
1618
1889
  * @example
1619
1890
  *
@@ -1625,8 +1896,14 @@ var LavalinkNode = class {
1625
1896
  */
1626
1897
  get: async (track, skipTrackSource = false) => {
1627
1898
  if (!this.sessionId) throw new Error("the Lavalink-Node is either not ready, or not up to date!");
1628
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin")) throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
1629
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasrc-plugin") && this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "java-lyrics-plugin")) throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
1899
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin"))
1900
+ throw new RangeError(
1901
+ `there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`
1902
+ );
1903
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasrc-plugin") && this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "java-lyrics-plugin"))
1904
+ throw new RangeError(
1905
+ `there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`
1906
+ );
1630
1907
  const url = `/lyrics?track=${track.encoded}&skipTrackSource=${skipTrackSource}`;
1631
1908
  return await this.request(url);
1632
1909
  },
@@ -1634,7 +1911,7 @@ var LavalinkNode = class {
1634
1911
  * Get the lyrics of the current playing track
1635
1912
  *
1636
1913
  * @param guildId the guild id of the player
1637
- * @param skipTrackSource whether to skip the track source or not
1914
+ * @param skipTrackSource wether to skip the track source or not
1638
1915
  * @returns the lyrics of the current playing track
1639
1916
  * @example
1640
1917
  * ```ts
@@ -1645,8 +1922,14 @@ var LavalinkNode = class {
1645
1922
  */
1646
1923
  getCurrent: async (guildId, skipTrackSource = false) => {
1647
1924
  if (!this.sessionId) throw new Error("the Lavalink-Node is either not ready, or not up to date!");
1648
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin")) throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
1649
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasrc-plugin") && this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "java-lyrics-plugin")) throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
1925
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin"))
1926
+ throw new RangeError(
1927
+ `there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`
1928
+ );
1929
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavasrc-plugin") && this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "java-lyrics-plugin"))
1930
+ throw new RangeError(
1931
+ `there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`
1932
+ );
1650
1933
  const url = `/sessions/${this.sessionId}/players/${guildId}/track/lyrics?skipTrackSource=${skipTrackSource}`;
1651
1934
  return await this.request(url);
1652
1935
  },
@@ -1664,7 +1947,10 @@ var LavalinkNode = class {
1664
1947
  */
1665
1948
  subscribe: async (guildId) => {
1666
1949
  if (!this.sessionId) throw new Error("the Lavalink-Node is either not ready, or not up to date!");
1667
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin")) throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
1950
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin"))
1951
+ throw new RangeError(
1952
+ `there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`
1953
+ );
1668
1954
  return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`, (options) => {
1669
1955
  options.method = "POST";
1670
1956
  });
@@ -1683,7 +1969,10 @@ var LavalinkNode = class {
1683
1969
  */
1684
1970
  unsubscribe: async (guildId) => {
1685
1971
  if (!this.sessionId) throw new Error("the Lavalink-Node is either not ready, or not up to date!");
1686
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin")) throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
1972
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "lavalyrics-plugin"))
1973
+ throw new RangeError(
1974
+ `there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`
1975
+ );
1687
1976
  return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`, (options) => {
1688
1977
  options.method = "DELETE";
1689
1978
  });
@@ -1711,7 +2000,10 @@ var LavalinkNode = class {
1711
2000
  * ```
1712
2001
  */
1713
2002
  async fetchConnectionMetrics() {
1714
- if (this.info && !this.info.isNodelink) throw new Error("There is no Information about whether you are using NodeLink instead of Lavalink, so this function won't work");
2003
+ if (this.info && !this.info.isNodelink)
2004
+ throw new Error(
2005
+ "There is no Information about wether you are using NodeLink instead of Lavalink, so this function won't work"
2006
+ );
1715
2007
  return await this.request(`/connection`);
1716
2008
  }
1717
2009
  /**
@@ -1724,9 +2016,13 @@ var LavalinkNode = class {
1724
2016
  * ```
1725
2017
  */
1726
2018
  async fetchVersion() {
1727
- return await this.request(`/version`, (r) => {
1728
- r.path = "/version";
1729
- }, true);
2019
+ return await this.request(
2020
+ `/version`,
2021
+ (r) => {
2022
+ r.path = "/version";
2023
+ },
2024
+ true
2025
+ );
1730
2026
  }
1731
2027
  /**
1732
2028
  * Request Lavalink information.
@@ -1742,6 +2038,160 @@ var LavalinkNode = class {
1742
2038
  async fetchInfo() {
1743
2039
  return await this.request(`/info`);
1744
2040
  }
2041
+ /**
2042
+ * Returns the metric summary of the node
2043
+ * @returns the metric summary of the node
2044
+ */
2045
+ nodeMetricSummary() {
2046
+ if (!this.connected || !this.isAlive)
2047
+ return {
2048
+ systemLoad: 0,
2049
+ cpuLoad: 0,
2050
+ memoryUsage: 0,
2051
+ players: 0,
2052
+ playingPlayers: 0,
2053
+ uptime: 0,
2054
+ ping: 0,
2055
+ frameDeficit: 0
2056
+ };
2057
+ const _memoryUsed = this.stats.memory.used;
2058
+ const _memoryAllocated = this.stats.memory.allocated;
2059
+ return {
2060
+ systemLoad: this.stats.cpu.systemLoad,
2061
+ cpuLoad: this.stats.cpu.lavalinkLoad,
2062
+ memoryUsage: _memoryAllocated > 0 ? _memoryUsed / _memoryAllocated * 100 : 0,
2063
+ players: this.stats.players,
2064
+ playingPlayers: this.stats.playingPlayers,
2065
+ uptime: this.stats.uptime,
2066
+ ping: this.heartBeatPing,
2067
+ frameDeficit: this.stats.frameStats?.deficit || 0
2068
+ };
2069
+ }
2070
+ /**
2071
+ * Get the node's health status with performance assessment.
2072
+ * @returns Object containing health status, performance rating, load balancing info, and recommendations
2073
+ *
2074
+ * @example
2075
+ * ```ts
2076
+ * const health = node.getHealthStatus();
2077
+ * console.log(`Node Status: ${health.status}`); // "healthy" | "degraded" | "critical" | "offline"
2078
+ * console.log(`Performance: ${health.performance}`); // "excellent" | "good" | "fair" | "poor"
2079
+ * console.log(`Penalty Score: ${health.penaltyScore}`); // Lower is better for load balancing
2080
+ * console.log(`Estimated Capacity: ${health.estimatedRemainingCapacity} more players`);
2081
+ * console.log(`Overloaded: ${health.isOverloaded}`);
2082
+ * console.log(`Needs Restart: ${health.needsRestart}`);
2083
+ * if (health.recommendations.length) {
2084
+ * console.log("Recommendations:", health.recommendations);
2085
+ * }
2086
+ * ```
2087
+ */
2088
+ getHealthStatus(thresholds) {
2089
+ const cpuThresholds = {
2090
+ excellent: 0.3,
2091
+ good: 0.5,
2092
+ fair: 0.7,
2093
+ poor: 0.85,
2094
+ ...thresholds?.cpu
2095
+ };
2096
+ const memoryThresholds = {
2097
+ excellent: 60,
2098
+ good: 75,
2099
+ fair: 85,
2100
+ poor: 95,
2101
+ ...thresholds?.memory
2102
+ };
2103
+ const pingThresholds = {
2104
+ excellent: 50,
2105
+ good: 100,
2106
+ fair: 200,
2107
+ poor: 300,
2108
+ ...thresholds?.ping
2109
+ };
2110
+ const recommendations = [];
2111
+ const metrics = this.nodeMetricSummary();
2112
+ if (!this.connected || !this.isAlive) {
2113
+ return {
2114
+ status: "offline",
2115
+ performance: "poor",
2116
+ isOverloaded: false,
2117
+ needsRestart: true,
2118
+ penaltyScore: 999999,
2119
+ // Maximum penalty for offline nodes
2120
+ estimatedRemainingCapacity: 0,
2121
+ recommendations: [RecommendationsStrings.nodeOffline, RecommendationsStrings.checkConnectivity],
2122
+ metrics
2123
+ };
2124
+ }
2125
+ let cpuScore = 0;
2126
+ if (metrics.cpuLoad < cpuThresholds.excellent) cpuScore = 4;
2127
+ else if (metrics.cpuLoad < cpuThresholds.good) cpuScore = 3;
2128
+ else if (metrics.cpuLoad < cpuThresholds.fair) cpuScore = 2;
2129
+ else if (metrics.cpuLoad < cpuThresholds.poor) cpuScore = 1;
2130
+ let memoryScore = 0;
2131
+ if (metrics.memoryUsage < memoryThresholds.excellent) memoryScore = 4;
2132
+ else if (metrics.memoryUsage < memoryThresholds.good) memoryScore = 3;
2133
+ else if (metrics.memoryUsage < memoryThresholds.fair) memoryScore = 2;
2134
+ else if (metrics.memoryUsage < memoryThresholds.poor) memoryScore = 1;
2135
+ let pingScore = 0;
2136
+ if (metrics.ping < pingThresholds.excellent) pingScore = 4;
2137
+ else if (metrics.ping < pingThresholds.good) pingScore = 3;
2138
+ else if (metrics.ping < pingThresholds.fair) pingScore = 2;
2139
+ else if (metrics.ping < pingThresholds.poor) pingScore = 1;
2140
+ const avgScore = (cpuScore + memoryScore + pingScore) / 3;
2141
+ let performance2 = "poor";
2142
+ if (avgScore >= 3.5) performance2 = "excellent";
2143
+ else if (avgScore >= 2.5) performance2 = "good";
2144
+ else if (avgScore >= 1.5) performance2 = "fair";
2145
+ const isOverloaded = metrics.cpuLoad > cpuThresholds.fair || metrics.memoryUsage > memoryThresholds.fair || metrics.frameDeficit > 100;
2146
+ const isCritical = metrics.cpuLoad > cpuThresholds.poor || metrics.memoryUsage > memoryThresholds.poor || metrics.frameDeficit > 500;
2147
+ const status = isCritical ? "critical" : isOverloaded ? "degraded" : "healthy";
2148
+ const needsRestart = status === "critical" || isOverloaded && metrics.memoryUsage > 90 || metrics.frameDeficit > 1e3 || this.reconnectionAttemptCount > 0 && this.reconnectionAttemptCount >= this.options.retryAmount / 2;
2149
+ if (metrics.cpuLoad > cpuThresholds.fair)
2150
+ recommendations.push(RecommendationsStrings.highCPULoad(metrics.cpuLoad));
2151
+ if (metrics.systemLoad > 0.8) recommendations.push(RecommendationsStrings.highSystemLoad(metrics.systemLoad));
2152
+ if (metrics.memoryUsage > memoryThresholds.fair)
2153
+ recommendations.push(RecommendationsStrings.highMemoryUsage(metrics.memoryUsage));
2154
+ if (metrics.frameDeficit > 100) recommendations.push(RecommendationsStrings.frameDeficit(metrics.frameDeficit));
2155
+ if (metrics.ping > pingThresholds.fair) recommendations.push(RecommendationsStrings.highLatency(metrics.ping));
2156
+ if (needsRestart) recommendations.push(RecommendationsStrings.nodeRestart);
2157
+ if (metrics.players > 500) recommendations.push(RecommendationsStrings.highPlayercount(metrics.players));
2158
+ const nullFrames = this.stats.frameStats?.nulled || 0;
2159
+ let penaltyScore = metrics.players + // Player count penalty (each player adds base penalty)
2160
+ Math.pow(metrics.cpuLoad * 100, 2) + // CPU penalty (exponential - heavily penalize high CPU)
2161
+ Math.pow(metrics.memoryUsage, 1.5) + // Memory penalty (exponential - heavily penalize high memory)
2162
+ metrics.ping * 2 + // Latency penalty
2163
+ metrics.frameDeficit * 10 + // Frame deficit penalty (critical for audio quality)
2164
+ nullFrames * 5;
2165
+ if (status === "critical") penaltyScore += 1e4;
2166
+ else if (status === "degraded") penaltyScore += 5e3;
2167
+ if (this.reconnectionAttemptCount > 0) penaltyScore += this.reconnectionAttemptCount * 1e3;
2168
+ penaltyScore = Math.round(penaltyScore);
2169
+ let estimatedRemainingCapacity = 0;
2170
+ if (status !== "critical") {
2171
+ const cpuCapacity = metrics.players === 0 ? 200 : metrics.cpuLoad > 0 ? Math.max(
2172
+ 0,
2173
+ Math.floor((cpuThresholds.fair - metrics.cpuLoad) / metrics.cpuLoad * metrics.players)
2174
+ ) : 200;
2175
+ const memoryCapacity = metrics.players === 0 ? 200 : metrics.memoryUsage > 0 ? Math.max(
2176
+ 0,
2177
+ Math.floor(
2178
+ (memoryThresholds.fair - metrics.memoryUsage) / metrics.memoryUsage * metrics.players
2179
+ )
2180
+ ) : 200;
2181
+ estimatedRemainingCapacity = Math.min(Math.min(cpuCapacity, memoryCapacity), 500);
2182
+ if (isOverloaded) estimatedRemainingCapacity = 0;
2183
+ }
2184
+ return {
2185
+ status,
2186
+ performance: performance2,
2187
+ isOverloaded,
2188
+ needsRestart,
2189
+ penaltyScore,
2190
+ estimatedRemainingCapacity,
2191
+ recommendations,
2192
+ metrics
2193
+ };
2194
+ }
1745
2195
  /**
1746
2196
  * Lavalink's Route Planner Api
1747
2197
  */
@@ -1801,6 +2251,44 @@ var LavalinkNode = class {
1801
2251
  if (!this.options.authorization) throw new SyntaxError("LavalinkNode requires 'authorization'");
1802
2252
  if (!this.options.host) throw new SyntaxError("LavalinkNode requires 'host'");
1803
2253
  if (!this.options.port) throw new SyntaxError("LavalinkNode requires 'port'");
2254
+ if (typeof this.options.port !== "number" || this.options.port < 1 || this.options.port > 65535)
2255
+ throw new SyntaxError("LavalinkNode.port must be a number within 1 and 65535");
2256
+ if (this.options.closeOnError !== void 0 && typeof this.options.closeOnError !== "boolean")
2257
+ throw new SyntaxError("LavalinkNode.closeOnError must be either false | true aka boolean");
2258
+ if (this.options.retryDelay !== void 0 && typeof this.options.retryDelay !== "number")
2259
+ throw new SyntaxError("LavalinkNodeOptions.retryDelay must be a number");
2260
+ if (this.options.retryAmount !== void 0 && typeof this.options.retryAmount !== "number")
2261
+ throw new SyntaxError("LavalinkNodeOptions.retryAmount must be a number");
2262
+ if (this.options.retryTimespan !== void 0 && typeof this.options.retryTimespan !== "number")
2263
+ throw new SyntaxError("LavalinkNodeOptions.retryTimespan must be a number");
2264
+ if (this.options.requestSignalTimeoutMS !== void 0 && typeof this.options.requestSignalTimeoutMS !== "number")
2265
+ throw new SyntaxError("LavalinkNodeOptions.requestSignalTimeoutMS must be a number");
2266
+ if (this.options.heartBeatInterval !== void 0 && typeof this.options.heartBeatInterval !== "number")
2267
+ throw new SyntaxError("LavalinkNodeOptions.heartBeatInterval must be a number");
2268
+ if (this.options.enablePingOnStatsCheck !== void 0 && typeof this.options.enablePingOnStatsCheck !== "boolean")
2269
+ throw new SyntaxError("LavalinkNodeOptions.enablePingOnStatsCheck must be either false | true aka boolean");
2270
+ if (this.options.autoChecks !== void 0 && typeof this.options.autoChecks !== "object")
2271
+ throw new SyntaxError("LavalinkNode.autoChecks must be an object");
2272
+ if (this.options?.autoChecks?.sourcesValidations !== void 0 && typeof this.options?.autoChecks?.sourcesValidations !== "boolean")
2273
+ throw new SyntaxError("LavalinkNode.autoChecks.sourcesValidations must be either false | true aka boolean");
2274
+ if (this.options?.autoChecks?.pluginValidations !== void 0 && typeof this.options?.autoChecks?.pluginValidations !== "boolean")
2275
+ throw new SyntaxError("LavalinkNode.autoChecks.pluginValidations must be either false | true aka boolean");
2276
+ if (this.options.regions !== void 0 && (!Array.isArray(this.options.regions) || !this.options.regions.every((r) => typeof r === "string")))
2277
+ throw new SyntaxError("LavalinkNode.regions must be an Array of strings");
2278
+ }
2279
+ /**
2280
+ * Checks if the node is a NodeLink node
2281
+ * @returns true if the node is a NodeLink node
2282
+ */
2283
+ isNodeLink() {
2284
+ return this.nodeType === "NodeLink";
2285
+ }
2286
+ /**
2287
+ * Checks if the node is a Lavalink node
2288
+ * @returns true if the node is a Lavalink node
2289
+ */
2290
+ isLavalinkNode() {
2291
+ return this.nodeType === "Lavalink";
1804
2292
  }
1805
2293
  /**
1806
2294
  * Sync the data of the player you make an action to lavalink to
@@ -1823,7 +2311,9 @@ var LavalinkNode = class {
1823
2311
  if (typeof data.playerOptions.voice !== "undefined") player.voice = data.playerOptions.voice;
1824
2312
  if (typeof data.playerOptions.volume !== "undefined") {
1825
2313
  if (this._LManager.options.playerOptions.volumeDecrementer) {
1826
- player.volume = Math.round(data.playerOptions.volume / this._LManager.options.playerOptions.volumeDecrementer);
2314
+ player.volume = Math.round(
2315
+ data.playerOptions.volume / this._LManager.options.playerOptions.volumeDecrementer
2316
+ );
1827
2317
  player.lavalinkVolume = Math.round(data.playerOptions.volume);
1828
2318
  } else {
1829
2319
  player.volume = Math.round(data.playerOptions.volume);
@@ -1833,16 +2323,26 @@ var LavalinkNode = class {
1833
2323
  if (typeof data.playerOptions.filters !== "undefined") {
1834
2324
  const oldFilterTimescale = { ...player.filterManager.data.timescale };
1835
2325
  Object.freeze(oldFilterTimescale);
1836
- if (data.playerOptions.filters.timescale) player.filterManager.data.timescale = data.playerOptions.filters.timescale;
1837
- if (data.playerOptions.filters.distortion) player.filterManager.data.distortion = data.playerOptions.filters.distortion;
1838
- if (data.playerOptions.filters.pluginFilters) player.filterManager.data.pluginFilters = data.playerOptions.filters.pluginFilters;
1839
- if (data.playerOptions.filters.vibrato) player.filterManager.data.vibrato = data.playerOptions.filters.vibrato;
1840
- if (data.playerOptions.filters.volume) player.filterManager.data.volume = data.playerOptions.filters.volume;
1841
- if (data.playerOptions.filters.equalizer) player.filterManager.equalizerBands = data.playerOptions.filters.equalizer;
1842
- if (data.playerOptions.filters.karaoke) player.filterManager.data.karaoke = data.playerOptions.filters.karaoke;
1843
- if (data.playerOptions.filters.lowPass) player.filterManager.data.lowPass = data.playerOptions.filters.lowPass;
1844
- if (data.playerOptions.filters.rotation) player.filterManager.data.rotation = data.playerOptions.filters.rotation;
1845
- if (data.playerOptions.filters.tremolo) player.filterManager.data.tremolo = data.playerOptions.filters.tremolo;
2326
+ if (data.playerOptions.filters.timescale)
2327
+ player.filterManager.data.timescale = data.playerOptions.filters.timescale;
2328
+ if (data.playerOptions.filters.distortion)
2329
+ player.filterManager.data.distortion = data.playerOptions.filters.distortion;
2330
+ if (data.playerOptions.filters.pluginFilters)
2331
+ player.filterManager.data.pluginFilters = data.playerOptions.filters.pluginFilters;
2332
+ if (data.playerOptions.filters.vibrato)
2333
+ player.filterManager.data.vibrato = data.playerOptions.filters.vibrato;
2334
+ if (data.playerOptions.filters.volume)
2335
+ player.filterManager.data.volume = data.playerOptions.filters.volume;
2336
+ if (data.playerOptions.filters.equalizer)
2337
+ player.filterManager.equalizerBands = data.playerOptions.filters.equalizer;
2338
+ if (data.playerOptions.filters.karaoke)
2339
+ player.filterManager.data.karaoke = data.playerOptions.filters.karaoke;
2340
+ if (data.playerOptions.filters.lowPass)
2341
+ player.filterManager.data.lowPass = data.playerOptions.filters.lowPass;
2342
+ if (data.playerOptions.filters.rotation)
2343
+ player.filterManager.data.rotation = data.playerOptions.filters.rotation;
2344
+ if (data.playerOptions.filters.tremolo)
2345
+ player.filterManager.data.tremolo = data.playerOptions.filters.tremolo;
1846
2346
  player.filterManager.checkFiltersState(oldFilterTimescale);
1847
2347
  }
1848
2348
  }
@@ -1871,7 +2371,7 @@ var LavalinkNode = class {
1871
2371
  }
1872
2372
  /**
1873
2373
  * Reconnect to the lavalink node
1874
- * @param force @default false Whether to instantly try to reconnect (force it)
2374
+ * @param force @default false Wether to instantly try to reconnect (force it)
1875
2375
  * @returns void
1876
2376
  *
1877
2377
  * @example
@@ -1896,14 +2396,13 @@ var LavalinkNode = class {
1896
2396
  }, this.options.retryDelay || 1e3);
1897
2397
  }
1898
2398
  get reconnectionAttemptCount() {
1899
- if (!Array.isArray(this.reconnectAttempts)) this.reconnectAttempts = [];
1900
2399
  const maxAllowedTimestan = this.options.retryTimespan || -1;
1901
2400
  if (maxAllowedTimestan <= 0) return this.reconnectAttempts.length;
1902
- return this.reconnectAttempts?.filter((timestamp) => Date.now() - timestamp <= maxAllowedTimestan).length || 0;
2401
+ return this.reconnectAttempts.filter((timestamp) => Date.now() - timestamp <= maxAllowedTimestan).length;
1903
2402
  }
1904
2403
  /**
1905
2404
  * Private Utility function to execute the reconnection
1906
- */
2405
+ */
1907
2406
  executeReconnect() {
1908
2407
  if (this.reconnectionAttemptCount >= this.options.retryAmount) {
1909
2408
  const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
@@ -1912,8 +2411,11 @@ var LavalinkNode = class {
1912
2411
  this.destroy("NodeReconnectFail" /* NodeReconnectFail */);
1913
2412
  return;
1914
2413
  }
1915
- if (!Array.isArray(this.reconnectAttempts)) this.reconnectAttempts = [];
2414
+ const MAX_RECONNECT_ATTEMPTS = 1e3;
1916
2415
  this.reconnectAttempts.push(Date.now());
2416
+ if (this.reconnectAttempts.length > MAX_RECONNECT_ATTEMPTS) {
2417
+ this.reconnectAttempts = this.reconnectAttempts.slice(-MAX_RECONNECT_ATTEMPTS);
2418
+ }
1917
2419
  this.reconnectionState = "RECONNECTING" /* RECONNECTING */;
1918
2420
  this.NodeManager.emit("reconnecting", this);
1919
2421
  this.connect();
@@ -1950,20 +2452,23 @@ var LavalinkNode = class {
1950
2452
  async open() {
1951
2453
  this.isAlive = true;
1952
2454
  this.resetReconnectionAttempts();
1953
- if (this.options.enablePingOnStatsCheck) this.heartBeat();
1954
- if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
1955
- if (this.options.heartBeatInterval > 0) {
1956
- this.socket.on("pong", () => {
1957
- this.heartBeatPongTimestamp = performance.now();
1958
- this.isAlive = true;
1959
- });
1960
- this.heartBeatInterval = setInterval(() => {
1961
- if (!this.socket) return console.error("Node-Heartbeat-Interval - Socket not available - maybe reconnecting?");
1962
- if (!this.isAlive) return this.close(500, "Node-Heartbeat-Timeout");
1963
- this.isAlive = false;
1964
- this.heartBeatPingTimestamp = performance.now();
1965
- this.socket?.ping?.();
1966
- }, this.options.heartBeatInterval || 3e4);
2455
+ if (this.nodeType === "Lavalink") {
2456
+ if (this.options.enablePingOnStatsCheck) this.heartBeat();
2457
+ if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
2458
+ if (this.options.heartBeatInterval > 0) {
2459
+ this.socket.on("pong", () => {
2460
+ this.heartBeatPongTimestamp = performance.now();
2461
+ this.isAlive = true;
2462
+ });
2463
+ this.heartBeatInterval = setInterval(() => {
2464
+ if (!this.socket)
2465
+ return console.error("Node-Heartbeat-Interval - Socket not available - maybe reconnecting?");
2466
+ if (!this.isAlive) return this.close(500, "Node-Heartbeat-Timeout");
2467
+ this.isAlive = false;
2468
+ this.heartBeatPingTimestamp = performance.now();
2469
+ this.socket?.ping?.();
2470
+ }, this.options.heartBeatInterval || 3e4);
2471
+ }
1967
2472
  }
1968
2473
  this.info = await this.fetchInfo().catch((e) => (console.error(e, "ON-OPEN-FETCH"), null));
1969
2474
  if (!this.info && ["v3", "v4"].includes(this.version)) {
@@ -2002,8 +2507,7 @@ var LavalinkNode = class {
2002
2507
  this._LManager.players.filter((p) => p?.node?.options?.id === this?.options?.id).forEach((p) => {
2003
2508
  if (!this._LManager.options.autoMove) return p.playing = false;
2004
2509
  if (this._LManager.options.autoMove) {
2005
- if (this.NodeManager.nodes.filter((n) => n.connected).size === 0)
2006
- return p.playing = false;
2510
+ if (this.NodeManager.nodes.filter((n) => n.connected).size === 0) return p.playing = false;
2007
2511
  p.moveNode();
2008
2512
  }
2009
2513
  });
@@ -2019,7 +2523,6 @@ var LavalinkNode = class {
2019
2523
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
2020
2524
  this.socket?.close(500, "Node-Error - Force Reconnect");
2021
2525
  }
2022
- ;
2023
2526
  }
2024
2527
  /** @private util function for handling message events from websocket */
2025
2528
  async message(d) {
@@ -2043,11 +2546,12 @@ var LavalinkNode = class {
2043
2546
  case "playerUpdate":
2044
2547
  {
2045
2548
  const player = this._LManager.getPlayer(payload.guildId);
2046
- if (!player) return this._emitDebugEvent("PlayerUpdateNoPlayer" /* PlayerUpdateNoPlayer */, {
2047
- state: "error",
2048
- message: `PlayerUpdate Event Triggered, but no player found of payload.guildId: ${payload.guildId}`,
2049
- functionLayer: "LavalinkNode > nodeEvent > playerUpdate"
2050
- });
2549
+ if (!player)
2550
+ return this._emitDebugEvent("PlayerUpdateNoPlayer" /* PlayerUpdateNoPlayer */, {
2551
+ state: "error",
2552
+ message: `PlayerUpdate Event Triggered, but no player found of payload.guildId: ${payload.guildId}`,
2553
+ functionLayer: "LavalinkNode > nodeEvent > playerUpdate"
2554
+ });
2051
2555
  const oldPlayer = player?.toJSON();
2052
2556
  player.lastPositionChange = Date.now();
2053
2557
  player.lastPosition = payload.state.position || 0;
@@ -2098,21 +2602,13 @@ var LavalinkNode = class {
2098
2602
  const player = this._LManager.getPlayer(payload.guildId);
2099
2603
  if (!player) return;
2100
2604
  const NodeLinkEventType = payload.type;
2101
- const NodeLinkExclusiveEvents = [
2102
- "PlayerCreatedEvent",
2103
- "PlayerDestroyedEvent",
2104
- "PlayerConnectedEvent",
2105
- "PlayerReconnectingEvent",
2106
- "VolumeChangedEvent",
2107
- "FiltersChangedEvent",
2108
- "SeekEvent",
2109
- "PauseEvent",
2110
- "ConnectionStatusEvent",
2111
- "MixStartedEvent",
2112
- "MixEndedEvent"
2113
- ];
2114
2605
  if (NodeLinkExclusiveEvents.includes(NodeLinkEventType) && (!this.info || this.info.isNodelink)) {
2115
- return this.nodeLinkEventHandler(NodeLinkEventType, player, player.queue.current, payload);
2606
+ return this.nodeLinkEventHandler(
2607
+ NodeLinkEventType,
2608
+ player,
2609
+ player.queue.current,
2610
+ payload
2611
+ );
2116
2612
  }
2117
2613
  switch (payload.type) {
2118
2614
  case "TrackStartEvent":
@@ -2152,7 +2648,12 @@ var LavalinkNode = class {
2152
2648
  this.LyricsNotFound(player, player.queue.current, payload);
2153
2649
  break;
2154
2650
  default:
2155
- this.NodeManager.emit("error", this, new Error(`Node#event unknown event '${payload.type}'.`), payload);
2651
+ this.NodeManager.emit(
2652
+ "error",
2653
+ this,
2654
+ new Error(`Node#event unknown event '${payload.type}'.`),
2655
+ payload
2656
+ );
2156
2657
  break;
2157
2658
  }
2158
2659
  return;
@@ -2211,7 +2712,8 @@ var LavalinkNode = class {
2211
2712
  this._LManager.emit("trackEnd", player, trackToUse, payload);
2212
2713
  return;
2213
2714
  }
2214
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying"))) return this.queueEnd(player, track, payload);
2715
+ if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
2716
+ return this.queueEnd(player, track, payload);
2215
2717
  if (["loadFailed", "cleanup"].includes(payload.reason)) {
2216
2718
  if (player.get("internal_destroystatus") === true) return;
2217
2719
  await queueTrackEnd(player);
@@ -2225,7 +2727,8 @@ var LavalinkNode = class {
2225
2727
  if (player.repeatMode !== "track" || player.get("internal_skipped")) await queueTrackEnd(player);
2226
2728
  else if (trackToUse && !trackToUse?.pluginInfo?.clientData?.previousTrack) {
2227
2729
  player.queue.previous.unshift(trackToUse);
2228
- if (player.queue.previous.length > player.queue.options.maxPreviousTracks) player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
2730
+ if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
2731
+ player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
2229
2732
  await player.queue.utils.save();
2230
2733
  }
2231
2734
  if (!player.queue.current) return this.queueEnd(player, trackToUse, payload);
@@ -2239,7 +2742,9 @@ var LavalinkNode = class {
2239
2742
  /** @private util function for handling trackStuck event */
2240
2743
  async trackStuck(player, track, payload) {
2241
2744
  if (this._LManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) {
2242
- const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || []).filter((v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold);
2745
+ const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || []).filter(
2746
+ (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2747
+ );
2243
2748
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2244
2749
  if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2245
2750
  this._emitDebugEvent("TrackStuckMaxTracksErroredPerTime" /* TrackStuckMaxTracksErroredPerTime */, {
@@ -2254,7 +2759,10 @@ var LavalinkNode = class {
2254
2759
  this._LManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
2255
2760
  if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying"))) {
2256
2761
  try {
2257
- await player.node.updatePlayer({ guildId: player.guildId, playerOptions: { track: { encoded: null } } });
2762
+ await player.node.updatePlayer({
2763
+ guildId: player.guildId,
2764
+ playerOptions: { track: { encoded: null } }
2765
+ });
2258
2766
  return;
2259
2767
  } catch {
2260
2768
  return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
@@ -2272,7 +2780,9 @@ var LavalinkNode = class {
2272
2780
  /** @private util function for handling trackError event */
2273
2781
  async trackError(player, track, payload) {
2274
2782
  if (this._LManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) {
2275
- const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || []).filter((v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold);
2783
+ const oldTimestamps = (player.get("internal_erroredTracksTimestamps") || []).filter(
2784
+ (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2785
+ );
2276
2786
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2277
2787
  if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2278
2788
  this._emitDebugEvent("TrackErrorMaxTracksErroredPerTime" /* TrackErrorMaxTracksErroredPerTime */, {
@@ -2324,8 +2834,11 @@ var LavalinkNode = class {
2324
2834
  * ```
2325
2835
  */
2326
2836
  async getSponsorBlock(player) {
2327
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "sponsorblock-plugin")) throw new RangeError(`there is no sponsorblock-plugin available in the lavalink node: ${this.id}`);
2328
- return await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`);
2837
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "sponsorblock-plugin"))
2838
+ throw new RangeError(`there is no sponsorblock-plugin available in the lavalink node: ${this.id}`);
2839
+ return await this.request(
2840
+ `/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`
2841
+ );
2329
2842
  }
2330
2843
  /**
2331
2844
  * Set the current sponsorblocks for the sponsorblock plugin
@@ -2339,15 +2852,25 @@ var LavalinkNode = class {
2339
2852
  * ```
2340
2853
  */
2341
2854
  async setSponsorBlock(player, segments = ["sponsor", "selfpromo"]) {
2342
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "sponsorblock-plugin")) throw new RangeError(`there is no sponsorblock-plugin available in the lavalink node: ${this.id}`);
2855
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "sponsorblock-plugin"))
2856
+ throw new RangeError(`there is no sponsorblock-plugin available in the lavalink node: ${this.id}`);
2343
2857
  if (!segments.length) throw new RangeError("No Segments provided. Did you ment to use 'deleteSponsorBlock'?");
2344
- if (segments.some((v) => !validSponsorBlocks.includes(v.toLowerCase()))) throw new SyntaxError(`You provided a sponsorblock which isn't valid, valid ones are: ${validSponsorBlocks.map((v) => `'${v}'`).join(", ")}`);
2858
+ if (segments.some((v) => !validSponsorBlocks.includes(v.toLowerCase())))
2859
+ throw new SyntaxError(
2860
+ `You provided a sponsorblock which isn't valid, valid ones are: ${validSponsorBlocks.map((v) => `'${v}'`).join(", ")}`
2861
+ );
2345
2862
  await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, (r) => {
2346
2863
  r.method = "PUT";
2347
- r.headers = { Authorization: this.options.authorization, "Content-Type": "application/json" };
2864
+ r.headers = {
2865
+ Authorization: this.options.authorization,
2866
+ "Content-Type": "application/json"
2867
+ };
2348
2868
  r.body = safeStringify(segments.map((v) => v.toLowerCase()));
2349
2869
  });
2350
- player.set("internal_sponsorBlockCategories", segments.map((v) => v.toLowerCase()));
2870
+ player.set(
2871
+ "internal_sponsorBlockCategories",
2872
+ segments.map((v) => v.toLowerCase())
2873
+ );
2351
2874
  this._emitDebugEvent("SetSponsorBlock" /* SetSponsorBlock */, {
2352
2875
  state: "log",
2353
2876
  message: `SponsorBlock was set for Player: ${player.guildId} to: ${segments.map((v) => `'${v.toLowerCase()}'`).join(", ")}`,
@@ -2367,7 +2890,8 @@ var LavalinkNode = class {
2367
2890
  * ```
2368
2891
  */
2369
2892
  async deleteSponsorBlock(player) {
2370
- if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "sponsorblock-plugin")) throw new RangeError(`there is no sponsorblock-plugin available in the lavalink node: ${this.id}`);
2893
+ if (this._checkForPlugins && !this.info?.plugins?.find?.((v) => v.name === "sponsorblock-plugin"))
2894
+ throw new RangeError(`there is no sponsorblock-plugin available in the lavalink node: ${this.id}`);
2371
2895
  await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, (r) => {
2372
2896
  r.method = "DELETE";
2373
2897
  });
@@ -2402,11 +2926,12 @@ var LavalinkNode = class {
2402
2926
  await this._LManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track);
2403
2927
  player.set("internal_previousautoplay", Date.now());
2404
2928
  if (player.queue.tracks.length > 0) await queueTrackEnd(player);
2405
- else this._emitDebugEvent("AutoplayNoSongsAdded" /* AutoplayNoSongsAdded */, {
2406
- state: "warn",
2407
- message: `Autoplay was triggered but no songs were added to the queue.`,
2408
- functionLayer: "LavalinkNode > queueEnd() > autoplayFunction"
2409
- });
2929
+ else
2930
+ this._emitDebugEvent("AutoplayNoSongsAdded" /* AutoplayNoSongsAdded */, {
2931
+ state: "warn",
2932
+ message: `Autoplay was triggered but no songs were added to the queue.`,
2933
+ functionLayer: "LavalinkNode > queueEnd() > autoplayFunction"
2934
+ });
2410
2935
  }
2411
2936
  if (player.queue.current) {
2412
2937
  if (payload.type === "TrackEndEvent") this._LManager.emit("trackEnd", player, track, payload);
@@ -2423,7 +2948,8 @@ var LavalinkNode = class {
2423
2948
  player.set("internal_autoplayStopPlaying", void 0);
2424
2949
  if (track && !track?.pluginInfo?.clientData?.previousTrack) {
2425
2950
  player.queue.previous.unshift(track);
2426
- if (player.queue.previous.length > player.queue.options.maxPreviousTracks) player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
2951
+ if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
2952
+ player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
2427
2953
  await player.queue.utils.save();
2428
2954
  }
2429
2955
  if (payload?.reason !== "stopped") {
@@ -2439,16 +2965,23 @@ var LavalinkNode = class {
2439
2965
  message: `Trigger Queue Empty Interval was Triggered because playerOptions.onEmptyQueue.destroyAfterMs is set to ${this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs}ms`,
2440
2966
  functionLayer: "LavalinkNode > queueEnd() > destroyAfterMs"
2441
2967
  });
2442
- this._LManager.emit("playerQueueEmptyStart", player, this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs);
2968
+ this._LManager.emit(
2969
+ "playerQueueEmptyStart",
2970
+ player,
2971
+ this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs
2972
+ );
2443
2973
  if (player.get("internal_queueempty")) clearTimeout(player.get("internal_queueempty"));
2444
- player.set("internal_queueempty", setTimeout(() => {
2445
- player.set("internal_queueempty", void 0);
2446
- if (player.queue.current) {
2447
- return this._LManager.emit("playerQueueEmptyCancel", player);
2448
- }
2449
- this._LManager.emit("playerQueueEmptyEnd", player);
2450
- player.destroy("QueueEmpty" /* QueueEmpty */);
2451
- }, this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs));
2974
+ player.set(
2975
+ "internal_queueempty",
2976
+ setTimeout(() => {
2977
+ player.set("internal_queueempty", void 0);
2978
+ if (player.queue.current) {
2979
+ return this._LManager.emit("playerQueueEmptyCancel", player);
2980
+ }
2981
+ this._LManager.emit("playerQueueEmptyEnd", player);
2982
+ player.destroy("QueueEmpty" /* QueueEmpty */);
2983
+ }, this._LManager.options.playerOptions.onEmptyQueue?.destroyAfterMs)
2984
+ );
2452
2985
  }
2453
2986
  }
2454
2987
  this._LManager.emit("queueEnd", player, track, payload);
@@ -2525,6 +3058,310 @@ var LavalinkNode = class {
2525
3058
  }
2526
3059
  };
2527
3060
 
3061
+ // src/structures/NodeLink.ts
3062
+ var NodeLinkNode = class extends LavalinkNode {
3063
+ nodeType = "NodeLink";
3064
+ constructor(options, manager) {
3065
+ super(options, manager);
3066
+ if (this.options.nodeType === "Lavalink" && this.constructor.name === "NodeLink") {
3067
+ return new LavalinkNode(options, manager);
3068
+ }
3069
+ this.nodeType = "NodeLink";
3070
+ }
3071
+ /**
3072
+ * Adds a new audio track to be mixed over the current playback.
3073
+ * @param player The player to add the mixer layer to.
3074
+ * @param trackToAdd The track to add to the mixer layer.
3075
+ * @param volume The volume of the track to add to the mixer layer. (0 - 100)
3076
+ * @link {https://nodelink.js.org/docs/api/rest#add-mix-layer} documentiation
3077
+ */
3078
+ async addMixerLayer(player, trackToAdd, volume) {
3079
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3080
+ return await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/mix`, (m) => {
3081
+ m.method = "POST";
3082
+ m.body = safeStringify({
3083
+ track: {
3084
+ encoded: trackToAdd.encoded,
3085
+ //identifier: trackToAdd.info?.identifier, // atm not supported
3086
+ userData: trackToAdd.userData
3087
+ },
3088
+ volume: (volume / 100).toFixed(2)
3089
+ });
3090
+ });
3091
+ }
3092
+ /**
3093
+ * Retrieves a list of currently active mix layers.
3094
+ * @param player The player to list the mixer layers for.
3095
+ * @link {https://nodelink.js.org/docs/api/rest#get-active-mixes} documentiation
3096
+ */
3097
+ async listMixerLayers(player) {
3098
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3099
+ return await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/mix`, (m) => {
3100
+ m.method = "GET";
3101
+ });
3102
+ }
3103
+ /**
3104
+ * Updates the volume of a specific mix layer.
3105
+ * @param player The player to update the mixer layer volume for.
3106
+ * @param mixId The ID of the mix layer to update.
3107
+ * @param volume The volume of the mix layer to update. (0 - 100)
3108
+ * @link {https://nodelink.js.org/docs/api/rest#update-mix-volume} documentiation
3109
+ */
3110
+ async updateMixerLayerVolume(player, mixId, volume) {
3111
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3112
+ await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/mix/${mixId}`, (m) => {
3113
+ m.method = "PATCH";
3114
+ m.body = safeStringify({
3115
+ volume: (volume / 100).toFixed(2)
3116
+ });
3117
+ });
3118
+ return true;
3119
+ }
3120
+ /**
3121
+ * Removes a specific mix layer.
3122
+ * @param player The player to remove the mix layer from.
3123
+ * @param mixId The ID of the mix layer to remove.
3124
+ * @link {https://nodelink.js.org/docs/api/rest#remove-mix-layer} documentiation
3125
+ */
3126
+ async removeMixerLayer(player, mixId) {
3127
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3128
+ await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/mix/${mixId}`, (m) => {
3129
+ m.method = "DELETE";
3130
+ });
3131
+ return true;
3132
+ }
3133
+ /**
3134
+ * @description
3135
+ * NodeLink has a lot of filters SPECIFICALLY for NodeLink, check the documentation for more information.
3136
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#additional-filters} documentiation
3137
+ */
3138
+ specificFilters = {
3139
+ /**
3140
+ * Creates delay-based echo with feedback control
3141
+ * @param player The player to apply the filter to
3142
+ * @param options The echo filter options
3143
+ */
3144
+ echo: async (player, options, disableFilter = false) => {
3145
+ if (disableFilter) delete player.filterManager.data.echo;
3146
+ else player.filterManager.data.echo = options;
3147
+ await player.filterManager.applyPlayerFilters();
3148
+ return player.filterManager.filters.nodeLinkEcho;
3149
+ },
3150
+ /**
3151
+ * Simulates multiple voices playing together with modulated delays
3152
+ * @param player The player to apply the filter to
3153
+ * @param options The chorus filter options
3154
+ */
3155
+ chorus: async (player, options, disableFilter = false) => {
3156
+ if (disableFilter) delete player.filterManager.data.chorus;
3157
+ else player.filterManager.data.chorus = options;
3158
+ await player.filterManager.applyPlayerFilters();
3159
+ return player.filterManager.filters.nodeLinkChorus;
3160
+ },
3161
+ /**
3162
+ * Dynamic range compression for balanced audio levels
3163
+ * @param player The player to apply the filter to
3164
+ * @param options The compressor filter options
3165
+ */
3166
+ compressor: async (player, options, disableFilter = false) => {
3167
+ if (disableFilter) delete player.filterManager.data.compressor;
3168
+ else player.filterManager.data.compressor = options;
3169
+ await player.filterManager.applyPlayerFilters();
3170
+ return player.filterManager.filters.nodeLinkCompressor;
3171
+ },
3172
+ /**
3173
+ * Filters out low frequencies, letting high frequencies pass through
3174
+ * @param player The player to apply the filter to
3175
+ * @param options The highpass filter options
3176
+ */
3177
+ highPass: async (player, options, disableFilter = false) => {
3178
+ if (disableFilter) delete player.filterManager.data.highPass;
3179
+ else player.filterManager.data.highPass = options;
3180
+ await player.filterManager.applyPlayerFilters();
3181
+ return player.filterManager.filters.nodeLinkHighPass;
3182
+ },
3183
+ /**
3184
+ * Sweeps all-pass filters across the frequency spectrum for a swooshing effect
3185
+ * @param player The player to apply the filter to
3186
+ * @param options The phaser filter options
3187
+ */
3188
+ phaser: async (player, options, disableFilter = false) => {
3189
+ if (disableFilter) delete player.filterManager.data.phaser;
3190
+ else player.filterManager.data.phaser = options;
3191
+ await player.filterManager.applyPlayerFilters();
3192
+ return player.filterManager.filters.nodeLinkPhaser;
3193
+ },
3194
+ /**
3195
+ * Creates spatial audio using cross-channel delays and modulation
3196
+ * @param player The player to apply the filter to
3197
+ * @param options The spatial filter options
3198
+ */
3199
+ spatial: async (player, options, disableFilter = false) => {
3200
+ if (disableFilter) delete player.filterManager.data.spatial;
3201
+ else player.filterManager.data.spatial = options;
3202
+ await player.filterManager.applyPlayerFilters();
3203
+ return player.filterManager.filters.nodeLinkSpatial;
3204
+ },
3205
+ /**
3206
+ * Resets all NodeLink filters
3207
+ * @param player The player to reset the filters for
3208
+ */
3209
+ resetNodeLinkFilters: async (player) => {
3210
+ delete player.filterManager.data.spatial;
3211
+ delete player.filterManager.data.echo;
3212
+ delete player.filterManager.data.chorus;
3213
+ delete player.filterManager.data.compressor;
3214
+ delete player.filterManager.data.highPass;
3215
+ delete player.filterManager.data.phaser;
3216
+ player.filterManager.checkFiltersState();
3217
+ await player.filterManager.applyPlayerFilters();
3218
+ return true;
3219
+ }
3220
+ };
3221
+ /**
3222
+ * Retrieve Lyrics of Youtube Videos.
3223
+ * @param player The Player you use with that node.
3224
+ * @param track if not provided, it will use the current track
3225
+ * @param language if not provided, it will use the default language (en)
3226
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#lyrics--chapters}
3227
+ * @returns NodeLinkLyrics either synced/unsynced or NodeLinkNoLyrics
3228
+ */
3229
+ async nodeLinkLyrics(player, track, language = "en") {
3230
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3231
+ const encodedTrack = track?.encoded || player.queue.current?.encoded;
3232
+ if (!encodedTrack) throw new Error("No track provided");
3233
+ return await this.request(
3234
+ `/sessions/${this.sessionId}/players/${player.guildId}/lyrics?encodedTrack=${encodedTrack}&lang=${language}`,
3235
+ (m) => {
3236
+ m.method = "GET";
3237
+ }
3238
+ );
3239
+ }
3240
+ /**
3241
+ * Retrieve Chapters of Youtube Videos.
3242
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#loadchapters}
3243
+ * @param player The Player you use with that node.
3244
+ * @param track if not provided, it will use the current track
3245
+ * @returns Array of NodeLinkChapter objects (if empty than there are no chapters available)
3246
+ */
3247
+ async getChapters(player, track) {
3248
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3249
+ const encodedTrack = track?.encoded || player.queue.current?.encoded;
3250
+ if (!encodedTrack) throw new Error("No track provided");
3251
+ return await this.request(
3252
+ `/sessions/${this.sessionId}/players/${player.guildId}/chapters?encodedTrack=${encodedTrack}`,
3253
+ (m) => {
3254
+ m.method = "GET";
3255
+ }
3256
+ );
3257
+ }
3258
+ /**
3259
+ * @link {https://nodelink.js.org/docs/api/rest#node-information}
3260
+ * @returns
3261
+ */
3262
+ async getConnectionMetrics() {
3263
+ return await this.request(`/connection`, (m) => {
3264
+ m.method = "GET";
3265
+ });
3266
+ }
3267
+ /**
3268
+ * Stream audio directly from NodeLink without Discord voice connection. | Note this must be enabled by NodeLink...
3269
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#direct-streaming}
3270
+ */
3271
+ async getDirectStream(track) {
3272
+ return await this.request(`/trackstream?encodedTrack=${track.encoded}`, (m) => {
3273
+ m.method = "GET";
3274
+ });
3275
+ }
3276
+ /**
3277
+ * Stream raw PCM audio for custom processing or recording.
3278
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#loadstream}
3279
+ * @param track The track to stream
3280
+ * @param volume The volume to stream at
3281
+ * @param position The position to stream from
3282
+ * @param filters The filters to apply to the stream
3283
+ * @returns Returns a raw PCM stream with Content-Type: audio/l16;rate=48000;channels=2.
3284
+ */
3285
+ async loadDirectStream(track, volume, position, filters) {
3286
+ let requestPath = `/loadstream?encodedTrack=${track.encoded}`;
3287
+ if (volume && volume > 0 && volume <= 100) requestPath += `&volume=${(volume / 100).toFixed(2)}`;
3288
+ if (position && position > 0) requestPath += `&position=${position}`;
3289
+ if (filters) requestPath += `&filters=${typeof filters === "object" ? safeStringify(filters) : filters}`;
3290
+ const res = await this.rawRequest(requestPath, (m) => {
3291
+ m.method = "GET";
3292
+ });
3293
+ return res.response;
3294
+ }
3295
+ /**
3296
+ * NodeLink supports selecting specific audio tracks for videos that contain multiple audio streams (e.g., Netflixstyle dubs, multi-language YouTube videos).
3297
+ * This function changes the current language of the audio, in place at the same position of the current track.
3298
+ * You can always do it manually by providing extra field in the track object "audioTrackId"
3299
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#additional-filters}
3300
+ * @param player The player to apply the filter to
3301
+ * @param language_audioTrackId The language of the audio track to select, see it in the pluginInfo.audioTracks
3302
+ */
3303
+ async changeAudioTrackLanguage(player, language_audioTrackId) {
3304
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3305
+ const res = await this.request(`/sessions/${this.sessionId}/players/${player.guildId}`, (r) => {
3306
+ r.method = "PATCH";
3307
+ r.headers["Content-Type"] = "application/json";
3308
+ r.body = safeStringify({
3309
+ track: {
3310
+ encoded: player.queue.current?.encoded,
3311
+ position: player.position,
3312
+ audioTrackId: language_audioTrackId
3313
+ }
3314
+ });
3315
+ });
3316
+ return res;
3317
+ }
3318
+ /**
3319
+ * Updates the YouTube configuration (RefreshToken or VisitorData) in real-time.
3320
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#update-config}
3321
+ */
3322
+ async updateYoutubeConfig(refreshToken, visitorData) {
3323
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3324
+ const res = await this.request(`/youtube/config`, (r) => {
3325
+ r.method = "PATCH";
3326
+ r.headers["Content-Type"] = "application/json";
3327
+ r.body = safeStringify({
3328
+ refreshToken,
3329
+ visitorData
3330
+ });
3331
+ });
3332
+ return res;
3333
+ }
3334
+ async getYoutubeConfig(validate = false) {
3335
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3336
+ const res = await this.request(`/youtube/config${validate ? "?validate=true" : ""}`, (r) => {
3337
+ r.method = "GET";
3338
+ });
3339
+ return res;
3340
+ }
3341
+ /**
3342
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#oauth}
3343
+ */
3344
+ async getYoutubeOAUTH(refreshToken) {
3345
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3346
+ return await this.request(`/youtube/oauth?refreshToken=${refreshToken}`, (m) => {
3347
+ m.method = "GET";
3348
+ });
3349
+ }
3350
+ /**
3351
+ * @link {https://nodelink.js.org/docs/api/nodelink-features#oauth}
3352
+ */
3353
+ async updateYoutubeOAUTH(refreshToken) {
3354
+ if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!");
3355
+ return await this.request(`/youtube/oauth`, (m) => {
3356
+ m.method = "POST";
3357
+ m.body = safeStringify({
3358
+ refreshToken
3359
+ });
3360
+ });
3361
+ }
3362
+ };
3363
+ LavalinkNode._NodeLinkClass = NodeLinkNode;
3364
+
2528
3365
  // src/structures/NodeManager.ts
2529
3366
  var NodeManager = class extends EventEmitter {
2530
3367
  /**
@@ -2586,9 +3423,10 @@ var NodeManager = class extends EventEmitter {
2586
3423
  constructor(LavalinkManager2) {
2587
3424
  super();
2588
3425
  this.LavalinkManager = LavalinkManager2;
2589
- if (this.LavalinkManager.options.nodes) this.LavalinkManager.options.nodes.forEach((node) => {
2590
- this.createNode(node);
2591
- });
3426
+ if (this.LavalinkManager.options.nodes)
3427
+ this.LavalinkManager.options.nodes.forEach((node) => {
3428
+ this.createNode(node);
3429
+ });
2592
3430
  }
2593
3431
  /**
2594
3432
  * Disconnects all Nodes from lavalink ws sockets
@@ -2598,7 +3436,8 @@ var NodeManager = class extends EventEmitter {
2598
3436
  */
2599
3437
  async disconnectAll(deleteAllNodes = false, destroyPlayers = true) {
2600
3438
  if (!this.nodes.size) throw new Error("There are no nodes to disconnect (no nodes in the nodemanager)");
2601
- if (!this.nodes.filter((v) => v.connected).size) throw new Error("There are no nodes to disconnect (all nodes disconnected)");
3439
+ if (!this.nodes.filter((v) => v.connected).size)
3440
+ throw new Error("There are no nodes to disconnect (all nodes disconnected)");
2602
3441
  let counter = 0;
2603
3442
  for (const node of this.nodes.values()) {
2604
3443
  if (!node.connected) continue;
@@ -2617,7 +3456,8 @@ var NodeManager = class extends EventEmitter {
2617
3456
  */
2618
3457
  async connectAll() {
2619
3458
  if (!this.nodes.size) throw new Error("There are no nodes to connect (no nodes in the nodemanager)");
2620
- if (!this.nodes.filter((v) => !v.connected).size) throw new Error("There are no nodes to connect (all nodes connected)");
3459
+ if (!this.nodes.filter((v) => !v.connected).size)
3460
+ throw new Error("There are no nodes to connect (all nodes connected)");
2621
3461
  let counter = 0;
2622
3462
  for (const node of this.nodes.values()) {
2623
3463
  if (node.connected) continue;
@@ -2647,8 +3487,9 @@ var NodeManager = class extends EventEmitter {
2647
3487
  * @returns The node that was created
2648
3488
  */
2649
3489
  createNode(options) {
2650
- if (this.nodes.has(options.id || `${options.host}:${options.port}`)) return this.nodes.get(options.id || `${options.host}:${options.port}`);
2651
- const newNode = new LavalinkNode(options, this);
3490
+ if (this.nodes.has(options.id || `${options.host}:${options.port}`))
3491
+ return this.nodes.get(options.id || `${options.host}:${options.port}`);
3492
+ const newNode = options.nodeType === "NodeLink" ? new NodeLinkNode(options, this) : new LavalinkNode(options, this);
2652
3493
  this.nodes.set(newNode.id, newNode);
2653
3494
  return newNode;
2654
3495
  }
@@ -2667,12 +3508,16 @@ var NodeManager = class extends EventEmitter {
2667
3508
  break;
2668
3509
  case "cpuLavalink":
2669
3510
  {
2670
- return connectedNodes.sort((a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0));
3511
+ return connectedNodes.sort(
3512
+ (a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0)
3513
+ );
2671
3514
  }
2672
3515
  break;
2673
3516
  case "cpuSystem":
2674
3517
  {
2675
- return connectedNodes.sort((a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0));
3518
+ return connectedNodes.sort(
3519
+ (a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0)
3520
+ );
2676
3521
  }
2677
3522
  break;
2678
3523
  case "calls":
@@ -2682,7 +3527,9 @@ var NodeManager = class extends EventEmitter {
2682
3527
  break;
2683
3528
  case "playingPlayers":
2684
3529
  {
2685
- return connectedNodes.sort((a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0));
3530
+ return connectedNodes.sort(
3531
+ (a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0)
3532
+ );
2686
3533
  }
2687
3534
  break;
2688
3535
  case "players":
@@ -2702,7 +3549,7 @@ var NodeManager = class extends EventEmitter {
2702
3549
  * @param node The node to delete
2703
3550
  * @param movePlayers whether to movePlayers to different connected node before deletion. @default false
2704
3551
  * @returns
2705
- *
3552
+ *
2706
3553
  * @example
2707
3554
  * Deletes the node
2708
3555
  * ```ts
@@ -2723,13 +3570,25 @@ var NodeManager = class extends EventEmitter {
2723
3570
  this.nodes.delete(decodeNode.id);
2724
3571
  return;
2725
3572
  }
3573
+ /**
3574
+ * Get a node from the nodeManager
3575
+ * @param node The node to get
3576
+ * @returns The node that was retrieved
3577
+ */
3578
+ getNode(node) {
3579
+ const decodeNode = typeof node === "string" ? this.nodes.get(node) : node;
3580
+ if (!decodeNode) return void 0;
3581
+ if (decodeNode.nodeType === "NodeLink") return decodeNode;
3582
+ return decodeNode;
3583
+ }
2726
3584
  };
2727
3585
 
2728
3586
  // src/structures/CustomSearches/BandCampSearch.ts
2729
3587
  var bandCampSearch = async (player, query, requestUser) => {
2730
3588
  let error = null;
2731
3589
  let tracks = [];
2732
- if (player.LavalinkManager.options.advancedOptions.debugOptions.logCustomSearches) console.log(`Lavalink-Client-Debug | SEARCHING | - ${query} on lavalink-client`);
3590
+ if (player.LavalinkManager.options.advancedOptions.debugOptions.logCustomSearches)
3591
+ console.log(`Lavalink-Client-Debug | SEARCHING | - ${query} on lavalink-client`);
2733
3592
  player.LavalinkManager.utils.validateQueryString(player.node, query);
2734
3593
  try {
2735
3594
  const requestUrl = new URL("https://bandcamp.com/api/nusearch/2/autocomplete");
@@ -2737,7 +3596,7 @@ var bandCampSearch = async (player, query, requestUser) => {
2737
3596
  const data = await fetch(requestUrl.toString(), {
2738
3597
  headers: {
2739
3598
  "User-Agent": "android-async-http/1.4.1 (http://loopj.com/android-async-http)",
2740
- "Cookie": "$Version=1"
3599
+ Cookie: "$Version=1"
2741
3600
  }
2742
3601
  });
2743
3602
  if (!data.ok) throw new Error(`Bandcamp Error: ${data.statusText}`);
@@ -2747,13 +3606,18 @@ var bandCampSearch = async (player, query, requestUser) => {
2747
3606
  } catch {
2748
3607
  throw new Error("Invalid JSON response from Bandcamp");
2749
3608
  }
2750
- tracks = json?.results?.filter((x) => !!x && typeof x === "object" && "type" in x && x.type === "t").map?.((item) => player.LavalinkManager.utils.buildUnresolvedTrack({
2751
- uri: item.url || item.uri,
2752
- artworkUrl: item.img,
2753
- author: item.band_name,
2754
- title: item.name,
2755
- identifier: item.id ? `${item.id}` : item.url?.split("/")?.reverse()[0]
2756
- }, requestUser));
3609
+ tracks = json?.results?.filter((x) => !!x && typeof x === "object" && "type" in x && x.type === "t").map?.(
3610
+ (item) => player.LavalinkManager.utils.buildUnresolvedTrack(
3611
+ {
3612
+ uri: item.url || item.uri,
3613
+ artworkUrl: item.img,
3614
+ author: item.band_name,
3615
+ title: item.name,
3616
+ identifier: item.id ? `${item.id}` : item.url?.split("/")?.reverse()[0]
3617
+ },
3618
+ requestUser
3619
+ )
3620
+ );
2757
3621
  } catch (e) {
2758
3622
  error = e;
2759
3623
  }
@@ -2802,6 +3666,43 @@ var DEFAULT_FILTER_DATAS = {
2802
3666
  // 0 < x <= 1
2803
3667
  },
2804
3668
  channelMix: audioOutputsData.stereo,
3669
+ // NODELINK SPECIFIC
3670
+ echo: {
3671
+ delay: 0,
3672
+ feedback: 0,
3673
+ mix: 0
3674
+ },
3675
+ chorus: {
3676
+ rate: 0,
3677
+ depth: 0,
3678
+ delay: 0,
3679
+ mix: 0,
3680
+ feedback: 0
3681
+ },
3682
+ compressor: {
3683
+ threshold: 0,
3684
+ ratio: 1,
3685
+ attack: 0,
3686
+ release: 0,
3687
+ gain: 0
3688
+ },
3689
+ highPass: {
3690
+ smoothing: 0
3691
+ },
3692
+ phaser: {
3693
+ stages: 0,
3694
+ rate: 0,
3695
+ depth: 0,
3696
+ feedback: 0,
3697
+ mix: 0,
3698
+ minFrequency: 0,
3699
+ maxFrequency: 0
3700
+ },
3701
+ spatial: {
3702
+ depth: 0,
3703
+ rate: 0
3704
+ },
3705
+ // LAVALINK-FILTER-PLUGIN SPECIFIC
2805
3706
  pluginFilters: {
2806
3707
  "lavalink-filter-plugin": {
2807
3708
  echo: {
@@ -2827,12 +3728,12 @@ var DEFAULT_FILTER_DATAS = {
2827
3728
  // "cutoffFrequency": 284, // Integer, higher than zero, in Hz.
2828
3729
  // "boostFactor": 1.24389 // Float, higher than 0.0. This alters volume output. A value of 1.0 means no volume change.
2829
3730
  },
2830
- "normalization": {
3731
+ normalization: {
2831
3732
  // Attenuates peaking where peaks are defined as having a higher value than {maxAmplitude}.
2832
3733
  // "maxAmplitude": 0.6327, // Float, within the range of 0.0 - 1.0. A value of 0.0 mutes the output.
2833
3734
  // "adaptive": true // false
2834
3735
  },
2835
- "echo": {
3736
+ echo: {
2836
3737
  // Self-explanatory; provides an echo effect.
2837
3738
  // "echoLength": 0.5649, // Float, higher than 0.0, in seconds (1.0 = 1 second).
2838
3739
  // "decay": 0.4649 // Float, within the range of 0.0 - 1.0. A value of 1.0 means no decay, and a value of 0.0 means
@@ -2866,6 +3767,12 @@ var FilterManager = class {
2866
3767
  tremolo: false,
2867
3768
  vibrato: false,
2868
3769
  lowPass: false,
3770
+ nodeLinkEcho: false,
3771
+ nodeLinkChorus: false,
3772
+ nodeLinkCompressor: false,
3773
+ nodeLinkHighPass: false,
3774
+ nodeLinkPhaser: false,
3775
+ nodeLinkSpatial: false,
2869
3776
  lavalinkFilterPlugin: {
2870
3777
  echo: false,
2871
3778
  reverb: false
@@ -2882,21 +3789,6 @@ var FilterManager = class {
2882
3789
  data = structuredClone(DEFAULT_FILTER_DATAS);
2883
3790
  /** The Player assigned to this Filter Manager */
2884
3791
  player;
2885
- get _LManager() {
2886
- return this.player.LavalinkManager;
2887
- }
2888
- /**
2889
- * Returns whether the plugin validations are enabled or not
2890
- */
2891
- get _checkForPlugins() {
2892
- return !!this._LManager.options?.autoChecks?.pluginValidations;
2893
- }
2894
- /**
2895
- * Returns whether the source validations are enabled or not
2896
- */
2897
- get _checkForSources() {
2898
- return !!this._LManager.options?.autoChecks?.sourcesValidations;
2899
- }
2900
3792
  /** The Constructor for the FilterManager */
2901
3793
  constructor(player) {
2902
3794
  this.player = player;
@@ -2922,24 +3814,33 @@ var FilterManager = class {
2922
3814
  if (!this.filters.tremolo) delete sendData.tremolo;
2923
3815
  if (!this.filters.vibrato) delete sendData.vibrato;
2924
3816
  if (!this.filters.lavalinkFilterPlugin.echo) delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.echo;
2925
- if (!this.filters.lavalinkFilterPlugin.reverb) delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.reverb;
3817
+ if (!this.filters.lavalinkFilterPlugin.reverb)
3818
+ delete sendData.pluginFilters?.["lavalink-filter-plugin"]?.reverb;
2926
3819
  if (!this.filters.lavalinkLavaDspxPlugin.echo) delete sendData.pluginFilters?.echo;
2927
3820
  if (!this.filters.lavalinkLavaDspxPlugin.normalization) delete sendData.pluginFilters?.normalization;
2928
3821
  if (!this.filters.lavalinkLavaDspxPlugin.highPass) delete sendData.pluginFilters?.["high-pass"];
2929
3822
  if (!this.filters.lavalinkLavaDspxPlugin.lowPass) delete sendData.pluginFilters?.["low-pass"];
2930
- if (sendData.pluginFilters?.["lavalink-filter-plugin"] && Object.values(sendData.pluginFilters?.["lavalink-filter-plugin"]).length === 0) delete sendData.pluginFilters["lavalink-filter-plugin"];
3823
+ if (sendData.pluginFilters?.["lavalink-filter-plugin"] && Object.values(sendData.pluginFilters?.["lavalink-filter-plugin"]).length === 0)
3824
+ delete sendData.pluginFilters["lavalink-filter-plugin"];
2931
3825
  if (sendData.pluginFilters && Object.values(sendData.pluginFilters).length === 0) delete sendData.pluginFilters;
2932
3826
  if (!this.filters.lowPass) delete sendData.lowPass;
2933
3827
  if (!this.filters.karaoke) delete sendData.karaoke;
2934
3828
  if (!this.filters.rotation) delete sendData.rotation;
2935
3829
  if (this.filters.audioOutput === "stereo") delete sendData.channelMix;
3830
+ if (!this.filters.nodeLinkEcho) delete sendData.echo;
3831
+ if (!this.filters.nodeLinkChorus) delete sendData.chorus;
3832
+ if (!this.filters.nodeLinkCompressor) delete sendData.compressor;
3833
+ if (!this.filters.nodeLinkHighPass) delete sendData.highPass;
3834
+ if (!this.filters.nodeLinkPhaser) delete sendData.phaser;
3835
+ if (!this.filters.nodeLinkSpatial) delete sendData.spatial;
2936
3836
  if (Object.values(this.data.timescale ?? {}).every((v) => v === 1)) delete sendData.timescale;
2937
3837
  if (!this.player.node.sessionId) throw new Error("The Lavalink-Node is either not ready or not up to date");
2938
3838
  sendData.equalizer = [...this.equalizerBands];
2939
3839
  if (sendData.equalizer.length === 0) delete sendData.equalizer;
2940
3840
  for (const key of Object.keys(sendData)) {
2941
3841
  if (key === "pluginFilters") {
2942
- } else if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.(key)) delete sendData[key];
3842
+ } else if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.(key))
3843
+ delete sendData[key];
2943
3844
  }
2944
3845
  const now = performance.now();
2945
3846
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
@@ -2998,6 +3899,12 @@ var FilterManager = class {
2998
3899
  echo: Object.values(this.data.pluginFilters?.echo || {})?.length > 0 && typeof this.data.pluginFilters?.echo?.delay === "undefined"
2999
3900
  };
3000
3901
  this.filters.lowPass = this.privateNot0(this.data.lowPass?.smoothing);
3902
+ this.filters.nodeLinkEcho = this.privateNot0(this.data.echo?.delay) || this.privateNot0(this.data.echo?.feedback) || this.privateNot0(this.data.echo?.mix);
3903
+ 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);
3904
+ 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);
3905
+ this.filters.nodeLinkHighPass = this.privateNot0(this.data.highPass?.smoothing);
3906
+ 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);
3907
+ this.filters.nodeLinkSpatial = this.privateNot0(this.data.spatial?.depth) || this.privateNot0(this.data.spatial?.rate);
3001
3908
  this.filters.karaoke = Object.values(this.data.karaoke ?? {}).some((v) => v !== 0);
3002
3909
  if ((this.filters.nightcore || this.filters.vaporwave) && oldFilterTimescale) {
3003
3910
  if (oldFilterTimescale.pitch !== this.data.timescale?.pitch || oldFilterTimescale.rate !== this.data.timescale?.rate || oldFilterTimescale.speed !== this.data.timescale?.speed) {
@@ -3033,6 +3940,12 @@ var FilterManager = class {
3033
3940
  this.filters.karaoke = false;
3034
3941
  this.filters.karaoke = false;
3035
3942
  this.filters.volume = false;
3943
+ this.filters.nodeLinkEcho = false;
3944
+ this.filters.nodeLinkChorus = false;
3945
+ this.filters.nodeLinkCompressor = false;
3946
+ this.filters.nodeLinkHighPass = false;
3947
+ this.filters.nodeLinkPhaser = false;
3948
+ this.filters.nodeLinkSpatial = false;
3036
3949
  this.filters.audioOutput = "stereo";
3037
3950
  this.data = structuredClone(DEFAULT_FILTER_DATAS);
3038
3951
  await this.applyPlayerFilters();
@@ -3079,8 +3992,10 @@ var FilterManager = class {
3079
3992
  * ```
3080
3993
  */
3081
3994
  async setAudioOutput(type) {
3082
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("channelMix")) throw new Error("Node#Info#filters does not include the 'channelMix' Filter (Node has it not enable)");
3083
- if (!type || !audioOutputsData[type]) throw "Invalid audio type added, must be 'mono' / 'stereo' / 'left' / 'right'";
3995
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("channelMix"))
3996
+ throw new Error("Node#Info#filters does not include the 'channelMix' Filter (Node has it not enable)");
3997
+ if (!type || !audioOutputsData[type])
3998
+ throw "Invalid audio type added, must be 'mono' / 'stereo' / 'left' / 'right'";
3084
3999
  this.data = this.data ?? {};
3085
4000
  this.data.channelMix = audioOutputsData[type];
3086
4001
  this.filters.audioOutput = type;
@@ -3099,7 +4014,8 @@ var FilterManager = class {
3099
4014
  * ```
3100
4015
  */
3101
4016
  async setSpeed(speed = 1) {
3102
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale")) throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
4017
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale"))
4018
+ throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
3103
4019
  this.data = this.data ?? {};
3104
4020
  this.filters.nightcore = false;
3105
4021
  this.filters.vaporwave = false;
@@ -3120,7 +4036,8 @@ var FilterManager = class {
3120
4036
  * ```
3121
4037
  */
3122
4038
  async setPitch(pitch = 1) {
3123
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale")) throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
4039
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale"))
4040
+ throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
3124
4041
  this.data = this.data ?? {};
3125
4042
  this.filters.nightcore = false;
3126
4043
  this.filters.vaporwave = false;
@@ -3141,7 +4058,8 @@ var FilterManager = class {
3141
4058
  * ```
3142
4059
  */
3143
4060
  async setRate(rate = 1) {
3144
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale")) throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
4061
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale"))
4062
+ throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
3145
4063
  this.data = this.data ?? {};
3146
4064
  this.filters.nightcore = false;
3147
4065
  this.filters.vaporwave = false;
@@ -3165,7 +4083,8 @@ var FilterManager = class {
3165
4083
  * ```
3166
4084
  */
3167
4085
  async toggleRotation(rotationHz = 0.2) {
3168
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("rotation")) throw new Error("Node#Info#filters does not include the 'rotation' Filter (Node has it not enable)");
4086
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("rotation"))
4087
+ throw new Error("Node#Info#filters does not include the 'rotation' Filter (Node has it not enable)");
3169
4088
  this.data = this.data ?? {};
3170
4089
  this.data.rotation = this.filters.rotation ? DEFAULT_FILTER_DATAS.rotation : { rotationHz };
3171
4090
  this.filters.rotation = !this.filters.rotation;
@@ -3188,7 +4107,8 @@ var FilterManager = class {
3188
4107
  * ```
3189
4108
  */
3190
4109
  async toggleVibrato(frequency = 10, depth = 1) {
3191
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("vibrato")) throw new Error("Node#Info#filters does not include the 'vibrato' Filter (Node has it not enable)");
4110
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("vibrato"))
4111
+ throw new Error("Node#Info#filters does not include the 'vibrato' Filter (Node has it not enable)");
3192
4112
  this.data = this.data ?? {};
3193
4113
  this.data.vibrato = this.filters.vibrato ? DEFAULT_FILTER_DATAS.vibrato : { depth, frequency };
3194
4114
  this.filters.vibrato = !this.filters.vibrato;
@@ -3211,7 +4131,8 @@ var FilterManager = class {
3211
4131
  * ```
3212
4132
  */
3213
4133
  async toggleTremolo(frequency = 4, depth = 0.8) {
3214
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("tremolo")) throw new Error("Node#Info#filters does not include the 'tremolo' Filter (Node has it not enable)");
4134
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("tremolo"))
4135
+ throw new Error("Node#Info#filters does not include the 'tremolo' Filter (Node has it not enable)");
3215
4136
  this.data = this.data ?? {};
3216
4137
  this.data.tremolo = this.filters.tremolo ? DEFAULT_FILTER_DATAS.tremolo : { depth, frequency };
3217
4138
  this.filters.tremolo = !this.filters.tremolo;
@@ -3233,7 +4154,8 @@ var FilterManager = class {
3233
4154
  * ```
3234
4155
  */
3235
4156
  async toggleLowPass(smoothing = 20) {
3236
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("lowPass")) throw new Error("Node#Info#filters does not include the 'lowPass' Filter (Node has it not enable)");
4157
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("lowPass"))
4158
+ throw new Error("Node#Info#filters does not include the 'lowPass' Filter (Node has it not enable)");
3237
4159
  this.data = this.data ?? {};
3238
4160
  this.data.lowPass = this.filters.lowPass ? DEFAULT_FILTER_DATAS.lowPass : { smoothing };
3239
4161
  this.filters.lowPass = !this.filters.lowPass;
@@ -3260,8 +4182,10 @@ var FilterManager = class {
3260
4182
  * ```
3261
4183
  */
3262
4184
  toggleLowPass: async (boostFactor = 1, cutoffFrequency = 80) => {
3263
- if (this._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin")) throw new Error("Node#Info#plugins does not include the lavadspx plugin");
3264
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("low-pass")) throw new Error("Node#Info#filters does not include the 'low-pass' Filter (Node has it not enable)");
4185
+ if (this.player.node._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin"))
4186
+ throw new Error("Node#Info#plugins does not include the lavadspx plugin");
4187
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("low-pass"))
4188
+ throw new Error("Node#Info#filters does not include the 'low-pass' Filter (Node has it not enable)");
3265
4189
  this.data = this.data ?? {};
3266
4190
  this.data.pluginFilters = this.data.pluginFilters ?? {};
3267
4191
  if (this.filters.lavalinkLavaDspxPlugin.lowPass) delete this.data.pluginFilters["low-pass"];
@@ -3286,8 +4210,10 @@ var FilterManager = class {
3286
4210
  * ```
3287
4211
  */
3288
4212
  toggleHighPass: async (boostFactor = 1, cutoffFrequency = 80) => {
3289
- if (this._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin")) throw new Error("Node#Info#plugins does not include the lavadspx plugin");
3290
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("high-pass")) throw new Error("Node#Info#filters does not include the 'high-pass' Filter (Node has it not enable)");
4213
+ if (this.player.node._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin"))
4214
+ throw new Error("Node#Info#plugins does not include the lavadspx plugin");
4215
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("high-pass"))
4216
+ throw new Error("Node#Info#filters does not include the 'high-pass' Filter (Node has it not enable)");
3291
4217
  this.data = this.data ?? {};
3292
4218
  this.data.pluginFilters = this.data.pluginFilters ?? {};
3293
4219
  if (this.filters.lavalinkLavaDspxPlugin.highPass) delete this.data.pluginFilters["high-pass"];
@@ -3312,8 +4238,12 @@ var FilterManager = class {
3312
4238
  * ```
3313
4239
  */
3314
4240
  toggleNormalization: async (maxAmplitude = 0.75, adaptive = true) => {
3315
- if (this._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin")) throw new Error("Node#Info#plugins does not include the lavadspx plugin");
3316
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("normalization")) throw new Error("Node#Info#filters does not include the 'normalization' Filter (Node has it not enable)");
4241
+ if (this.player.node._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin"))
4242
+ throw new Error("Node#Info#plugins does not include the lavadspx plugin");
4243
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("normalization"))
4244
+ throw new Error(
4245
+ "Node#Info#filters does not include the 'normalization' Filter (Node has it not enable)"
4246
+ );
3317
4247
  this.data = this.data ?? {};
3318
4248
  this.data.pluginFilters = this.data.pluginFilters ?? {};
3319
4249
  if (this.filters.lavalinkLavaDspxPlugin.normalization) delete this.data.pluginFilters.normalization;
@@ -3338,8 +4268,10 @@ var FilterManager = class {
3338
4268
  * ```
3339
4269
  */
3340
4270
  toggleEcho: async (decay = 0.5, echoLength = 0.5) => {
3341
- if (this._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin")) throw new Error("Node#Info#plugins does not include the lavadspx plugin");
3342
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("echo")) throw new Error("Node#Info#filters does not include the 'echo' Filter (Node has it not enable)");
4271
+ if (this.player.node._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavadspx-plugin"))
4272
+ throw new Error("Node#Info#plugins does not include the lavadspx plugin");
4273
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("echo"))
4274
+ throw new Error("Node#Info#filters does not include the 'echo' Filter (Node has it not enable)");
3343
4275
  this.data = this.data ?? {};
3344
4276
  this.data.pluginFilters = this.data.pluginFilters ?? {};
3345
4277
  if (this.filters.lavalinkLavaDspxPlugin.echo) delete this.data.pluginFilters.echo;
@@ -3369,8 +4301,12 @@ var FilterManager = class {
3369
4301
  * ```
3370
4302
  */
3371
4303
  toggleEcho: async (delay = 4, decay = 0.8) => {
3372
- if (this._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavalink-filter-plugin")) throw new Error("Node#Info#plugins does not include the lavalink-filter-plugin plugin");
3373
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("echo")) throw new Error("Node#Info#filters does not include the 'echo' Filter (Node has it not enable aka not installed!)");
4304
+ if (this.player.node._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavalink-filter-plugin"))
4305
+ throw new Error("Node#Info#plugins does not include the lavalink-filter-plugin plugin");
4306
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("echo"))
4307
+ throw new Error(
4308
+ "Node#Info#filters does not include the 'echo' Filter (Node has it not enable aka not installed!)"
4309
+ );
3374
4310
  this.data = this.data ?? {};
3375
4311
  const { echo, reverb } = DEFAULT_FILTER_DATAS.pluginFilters["lavalink-filter-plugin"];
3376
4312
  this.data.pluginFilters = {
@@ -3400,8 +4336,12 @@ var FilterManager = class {
3400
4336
  * ```
3401
4337
  */
3402
4338
  toggleReverb: async (delays = [0.037, 0.042, 0.048, 0.053], gains = [0.84, 0.83, 0.82, 0.81]) => {
3403
- if (this._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavalink-filter-plugin")) throw new Error("Node#Info#plugins does not include the lavalink-filter-plugin plugin");
3404
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("reverb")) throw new Error("Node#Info#filters does not include the 'reverb' Filter (Node has it not enable aka not installed!)");
4339
+ if (this.player.node._checkForPlugins && !this.player?.node?.info?.plugins?.find?.((v) => v.name === "lavalink-filter-plugin"))
4340
+ throw new Error("Node#Info#plugins does not include the lavalink-filter-plugin plugin");
4341
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("reverb"))
4342
+ throw new Error(
4343
+ "Node#Info#filters does not include the 'reverb' Filter (Node has it not enable aka not installed!)"
4344
+ );
3405
4345
  this.data = this.data ?? {};
3406
4346
  const { echo, reverb } = DEFAULT_FILTER_DATAS.pluginFilters["lavalink-filter-plugin"];
3407
4347
  this.data.pluginFilters = {
@@ -3433,7 +4373,8 @@ var FilterManager = class {
3433
4373
  * ```
3434
4374
  */
3435
4375
  async toggleNightcore(speed = 1.289999523162842, pitch = 1.289999523162842, rate = 0.9365999523162842) {
3436
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale")) throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
4376
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale"))
4377
+ throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
3437
4378
  this.data = this.data ?? {};
3438
4379
  this.data.timescale = this.filters.nightcore ? DEFAULT_FILTER_DATAS.timescale : { speed, pitch, rate };
3439
4380
  this.filters.nightcore = !this.filters.nightcore;
@@ -3459,7 +4400,8 @@ var FilterManager = class {
3459
4400
  * ```
3460
4401
  */
3461
4402
  async toggleVaporwave(speed = 0.8500000238418579, pitch = 0.800000011920929, rate = 1) {
3462
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale")) throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
4403
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("timescale"))
4404
+ throw new Error("Node#Info#filters does not include the 'timescale' Filter (Node has it not enable)");
3463
4405
  this.data = this.data ?? {};
3464
4406
  this.data.timescale = this.filters.vaporwave ? DEFAULT_FILTER_DATAS.timescale : { speed, pitch, rate };
3465
4407
  this.filters.vaporwave = !this.filters.vaporwave;
@@ -3486,7 +4428,8 @@ var FilterManager = class {
3486
4428
  * ```
3487
4429
  */
3488
4430
  async toggleKaraoke(level = 1, monoLevel = 1, filterBand = 220, filterWidth = 100) {
3489
- if (this._checkForSources && !this.player?.node?.info?.filters?.includes?.("karaoke")) throw new Error("Node#Info#filters does not include the 'karaoke' Filter (Node has it not enable)");
4431
+ if (this.player.node._checkForSources && !this.player?.node?.info?.filters?.includes?.("karaoke"))
4432
+ throw new Error("Node#Info#filters does not include the 'karaoke' Filter (Node has it not enable)");
3490
4433
  this.data = this.data ?? {};
3491
4434
  this.data.karaoke = this.filters.karaoke ? DEFAULT_FILTER_DATAS.karaoke : { level, monoLevel, filterBand, filterWidth };
3492
4435
  this.filters.karaoke = !this.filters.karaoke;
@@ -3543,7 +4486,8 @@ var FilterManager = class {
3543
4486
  */
3544
4487
  async setEQ(bands) {
3545
4488
  if (!Array.isArray(bands)) bands = [bands];
3546
- if (!bands.length || !bands.every((band) => safeStringify(Object.keys(band).sort()) === '["band","gain"]')) throw new TypeError("Bands must be a non-empty object array containing 'band' and 'gain' properties.");
4489
+ if (!bands.length || !bands.every((band) => safeStringify(Object.keys(band).sort()) === '["band","gain"]'))
4490
+ throw new TypeError("Bands must be a non-empty object array containing 'band' and 'gain' properties.");
3547
4491
  for (const { band, gain } of bands) this.equalizerBands[band] = { band, gain };
3548
4492
  if (!this.player.node.sessionId) throw new Error("The Lavalink-Node is either not ready or not up to date");
3549
4493
  const now = performance.now();
@@ -3709,8 +4653,14 @@ var Queue = class {
3709
4653
  this.QueueSaver = QueueSaver2;
3710
4654
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
3711
4655
  this.current = this.managerUtils.isTrack(data.current) ? data.current : null;
3712
- this.previous = Array.isArray(data.previous) && data.previous.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.previous.filter((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
3713
- this.tracks = Array.isArray(data.tracks) && data.tracks.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.tracks.filter((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
4656
+ this.previous = Array.isArray(data.previous) && data.previous.some(
4657
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4658
+ ) ? data.previous.filter(
4659
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4660
+ ) : [];
4661
+ this.tracks = Array.isArray(data.tracks) && data.tracks.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.tracks.filter(
4662
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4663
+ ) : [];
3714
4664
  Object.defineProperty(this, QueueSymbol, { configurable: true, value: true });
3715
4665
  }
3716
4666
  /**
@@ -3721,7 +4671,8 @@ var Queue = class {
3721
4671
  * Save the current cached Queue on the database/server (overides the server)
3722
4672
  */
3723
4673
  save: async () => {
3724
- if (this.previous.length > this.options.maxPreviousTracks) this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
4674
+ if (this.previous.length > this.options.maxPreviousTracks)
4675
+ this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
3725
4676
  return await this.QueueSaver.set(this.guildId, this.utils.toJSON());
3726
4677
  },
3727
4678
  /**
@@ -3731,9 +4682,28 @@ var Queue = class {
3731
4682
  sync: async (override = true, dontSyncCurrent = true) => {
3732
4683
  const data = await this.QueueSaver.get(this.guildId);
3733
4684
  if (!data) throw new Error(`No data found to sync for guildId: ${this.guildId}`);
3734
- if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current)) this.current = data.current;
3735
- 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)));
3736
- if (Array.isArray(data.previous) && data?.previous.length && data.previous.some((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track))) this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter((track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
4685
+ if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current))
4686
+ this.current = data.current;
4687
+ if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(
4688
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4689
+ ))
4690
+ this.tracks.splice(
4691
+ override ? 0 : this.tracks.length,
4692
+ override ? this.tracks.length : 0,
4693
+ ...data.tracks.filter(
4694
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4695
+ )
4696
+ );
4697
+ if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(
4698
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4699
+ ))
4700
+ this.previous.splice(
4701
+ 0,
4702
+ override ? this.tracks.length : 0,
4703
+ ...data.previous.filter(
4704
+ (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4705
+ )
4706
+ );
3737
4707
  await this.utils.save();
3738
4708
  return;
3739
4709
  },
@@ -3744,7 +4714,8 @@ var Queue = class {
3744
4714
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
3745
4715
  */
3746
4716
  toJSON: () => {
3747
- if (this.previous.length > this.options.maxPreviousTracks) this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
4717
+ if (this.previous.length > this.options.maxPreviousTracks)
4718
+ this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
3748
4719
  return {
3749
4720
  current: this.current ? { ...this.current } : null,
3750
4721
  previous: this.previous ? [...this.previous] : [],
@@ -3756,25 +4727,28 @@ var Queue = class {
3756
4727
  * @returns {number}
3757
4728
  */
3758
4729
  totalDuration: () => {
3759
- return this.tracks.reduce((acc, cur) => acc + (cur.info.duration || 0), this.current?.info.duration || 0);
4730
+ return this.tracks.reduce(
4731
+ (acc, cur) => acc + (cur.info.duration || 0),
4732
+ this.current?.info.duration || 0
4733
+ );
3760
4734
  },
3761
4735
  /**
3762
4736
  * Find tracks in the queue matching specific criteria.
3763
4737
  * **This method DOES NOT MUTATE the queue** - it returns a new array without modifying the original queue.
3764
4738
  * @param predicate Function to test each track, or an object with criteria to match
3765
4739
  * @returns Array of matching tracks with their indexes
3766
- *
4740
+ *
3767
4741
  * @example
3768
4742
  * ```ts
3769
4743
  * // Find by author
3770
4744
  * const artistTracks = player.queue.utils.filterTracks({ author: "Artist Name" });
3771
- *
4745
+ *
3772
4746
  * // Find by duration range (5-10 minutes)
3773
4747
  * const longTracks = player.queue.utils.filterTracks({ duration: { min: 300000, max: 600000 } });
3774
- *
4748
+ *
3775
4749
  * // Find by title (partial match)
3776
4750
  * const titleMatches = player.queue.utils.filterTracks({ title: "Never Gonna" });
3777
- *
4751
+ *
3778
4752
  * // Custom predicate
3779
4753
  * const customFilter = player.queue.utils.filterTracks(track => track.info.isStream);
3780
4754
  * ```
@@ -3822,7 +4796,7 @@ var Queue = class {
3822
4796
  * **This method DOES NOT MUTATE the queue** - it searches without modifying the original queue.
3823
4797
  * @param predicate Function to test each track, or an object with criteria to match
3824
4798
  * @returns First matching track with its index, or null if not found
3825
- *
4799
+ *
3826
4800
  * @example
3827
4801
  * ```ts
3828
4802
  * // Find first track by author
@@ -3830,7 +4804,7 @@ var Queue = class {
3830
4804
  * if (track) {
3831
4805
  * console.log(`Found at index ${track.index}: ${track.track.info.title}`);
3832
4806
  * }
3833
- *
4807
+ *
3834
4808
  * // Find with custom predicate
3835
4809
  * const liveStream = player.queue.utils.findTrack(track => track.info.isStream);
3836
4810
  * ```
@@ -3855,7 +4829,8 @@ var Queue = class {
3855
4829
  [this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]];
3856
4830
  }
3857
4831
  }
3858
- if (typeof this.queueChanges?.shuffled === "function") this.queueChanges.shuffled(this.guildId, oldStored, this.utils.toJSON());
4832
+ if (typeof this.queueChanges?.shuffled === "function")
4833
+ this.queueChanges.shuffled(this.guildId, oldStored, this.utils.toJSON());
3859
4834
  await this.utils.save();
3860
4835
  return this.tracks.length;
3861
4836
  }
@@ -3867,14 +4842,27 @@ var Queue = class {
3867
4842
  */
3868
4843
  async add(TrackOrTracks, index) {
3869
4844
  if (typeof index === "number" && index >= 0 && index < this.tracks.length) {
3870
- return await this.splice(index, 0, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
4845
+ return await this.splice(
4846
+ index,
4847
+ 0,
4848
+ (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))
4849
+ );
3871
4850
  }
3872
4851
  const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.toJSON() : null;
3873
- this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
3874
- if (typeof this.queueChanges?.tracksAdd === "function") try {
3875
- this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), this.tracks.length, oldStored, this.utils.toJSON());
3876
- } catch {
3877
- }
4852
+ this.tracks.push(
4853
+ ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))
4854
+ );
4855
+ if (typeof this.queueChanges?.tracksAdd === "function")
4856
+ try {
4857
+ this.queueChanges.tracksAdd(
4858
+ this.guildId,
4859
+ (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)),
4860
+ this.tracks.length,
4861
+ oldStored,
4862
+ this.utils.toJSON()
4863
+ );
4864
+ } catch {
4865
+ }
3878
4866
  await this.utils.save();
3879
4867
  return this.tracks.length;
3880
4868
  }
@@ -3891,19 +4879,27 @@ var Queue = class {
3891
4879
  if (TrackOrTracks) return await this.add(TrackOrTracks);
3892
4880
  return null;
3893
4881
  }
3894
- if (TrackOrTracks && typeof this.queueChanges?.tracksAdd === "function") try {
3895
- this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), index, oldStored, this.utils.toJSON());
3896
- } catch {
3897
- }
4882
+ if (TrackOrTracks && typeof this.queueChanges?.tracksAdd === "function")
4883
+ try {
4884
+ this.queueChanges.tracksAdd(
4885
+ this.guildId,
4886
+ (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)),
4887
+ index,
4888
+ oldStored,
4889
+ this.utils.toJSON()
4890
+ );
4891
+ } catch {
4892
+ }
3898
4893
  const spliced = TrackOrTracks ? this.tracks.splice(
3899
4894
  index,
3900
4895
  amount,
3901
4896
  ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))
3902
4897
  ) : this.tracks.splice(index, amount);
3903
- if (typeof this.queueChanges?.tracksRemoved === "function") try {
3904
- this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
3905
- } catch {
3906
- }
4898
+ if (typeof this.queueChanges?.tracksRemoved === "function")
4899
+ try {
4900
+ this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
4901
+ } catch {
4902
+ }
3907
4903
  await this.utils.save();
3908
4904
  return spliced.length === 1 ? spliced[0] : spliced;
3909
4905
  }
@@ -3948,10 +4944,17 @@ var Queue = class {
3948
4944
  const toRemove2 = this.tracks[removeQueryTrack];
3949
4945
  if (!toRemove2) return null;
3950
4946
  const removed2 = this.tracks.splice(removeQueryTrack, 1);
3951
- if (typeof this.queueChanges?.tracksRemoved === "function") try {
3952
- this.queueChanges.tracksRemoved(this.guildId, removed2, removeQueryTrack, oldStored, this.utils.toJSON());
3953
- } catch {
3954
- }
4947
+ if (typeof this.queueChanges?.tracksRemoved === "function")
4948
+ try {
4949
+ this.queueChanges.tracksRemoved(
4950
+ this.guildId,
4951
+ removed2,
4952
+ removeQueryTrack,
4953
+ oldStored,
4954
+ this.utils.toJSON()
4955
+ );
4956
+ } catch {
4957
+ }
3955
4958
  await this.utils.save();
3956
4959
  return { removed: removed2 };
3957
4960
  }
@@ -3965,16 +4968,25 @@ var Queue = class {
3965
4968
  }
3966
4969
  }
3967
4970
  if (!removed3.length) return null;
3968
- if (typeof this.queueChanges?.tracksRemoved === "function") try {
3969
- this.queueChanges.tracksRemoved(this.guildId, removed3, removeQueryTrack, oldStored, this.utils.toJSON());
3970
- } catch {
3971
- }
4971
+ if (typeof this.queueChanges?.tracksRemoved === "function")
4972
+ try {
4973
+ this.queueChanges.tracksRemoved(
4974
+ this.guildId,
4975
+ removed3,
4976
+ removeQueryTrack,
4977
+ oldStored,
4978
+ this.utils.toJSON()
4979
+ );
4980
+ } catch {
4981
+ }
3972
4982
  await this.utils.save();
3973
4983
  return { removed: removed3 };
3974
4984
  }
3975
- const tracksToRemove = this.tracks.map((v, i) => ({ v, i })).filter(({ v, i }) => removeQueryTrack.find(
3976
- (t) => typeof t === "number" && t === i || typeof t === "object" && (t.encoded && t.encoded === v.encoded || t.info?.identifier && t.info.identifier === v.info?.identifier || t.info?.uri && t.info.uri === v.info?.uri || t.info?.title && t.info.title === v.info?.title || t.info?.isrc && t.info.isrc === v.info?.isrc || t.info?.artworkUrl && t.info.artworkUrl === v.info?.artworkUrl)
3977
- ));
4985
+ const tracksToRemove = this.tracks.map((v, i) => ({ v, i })).filter(
4986
+ ({ v, i }) => removeQueryTrack.find(
4987
+ (t) => typeof t === "number" && t === i || typeof t === "object" && (t.encoded && t.encoded === v.encoded || t.info?.identifier && t.info.identifier === v.info?.identifier || t.info?.uri && t.info.uri === v.info?.uri || t.info?.title && t.info.title === v.info?.title || t.info?.isrc && t.info.isrc === v.info?.isrc || t.info?.artworkUrl && t.info.artworkUrl === v.info?.artworkUrl)
4988
+ )
4989
+ );
3978
4990
  if (!tracksToRemove.length) return null;
3979
4991
  const removed2 = [];
3980
4992
  tracksToRemove.sort((a, b) => b.i - a.i);
@@ -3983,10 +4995,17 @@ var Queue = class {
3983
4995
  removed2.unshift(...this.tracks.splice(i, 1));
3984
4996
  }
3985
4997
  }
3986
- if (typeof this.queueChanges?.tracksRemoved === "function") try {
3987
- this.queueChanges.tracksRemoved(this.guildId, removed2, tracksToRemove.map((v) => v.i), oldStored, this.utils.toJSON());
3988
- } catch {
3989
- }
4998
+ if (typeof this.queueChanges?.tracksRemoved === "function")
4999
+ try {
5000
+ this.queueChanges.tracksRemoved(
5001
+ this.guildId,
5002
+ removed2,
5003
+ tracksToRemove.map((v) => v.i),
5004
+ oldStored,
5005
+ this.utils.toJSON()
5006
+ );
5007
+ } catch {
5008
+ }
3990
5009
  await this.utils.save();
3991
5010
  return { removed: removed2 };
3992
5011
  }
@@ -3995,10 +5014,11 @@ var Queue = class {
3995
5014
  );
3996
5015
  if (toRemove < 0) return null;
3997
5016
  const removed = this.tracks.splice(toRemove, 1);
3998
- if (typeof this.queueChanges?.tracksRemoved === "function") try {
3999
- this.queueChanges.tracksRemoved(this.guildId, removed, toRemove, oldStored, this.utils.toJSON());
4000
- } catch {
4001
- }
5017
+ if (typeof this.queueChanges?.tracksRemoved === "function")
5018
+ try {
5019
+ this.queueChanges.tracksRemoved(this.guildId, removed, toRemove, oldStored, this.utils.toJSON());
5020
+ } catch {
5021
+ }
4002
5022
  await this.utils.save();
4003
5023
  return { removed };
4004
5024
  }
@@ -4025,7 +5045,7 @@ var Queue = class {
4025
5045
  * @deprecated Use `player.queue.utils.filterTracks()` instead.
4026
5046
  * @param predicate Function to test each track, or an object with criteria to match
4027
5047
  * @returns Array of matching tracks with their indexes
4028
- *
5048
+ *
4029
5049
  * @example
4030
5050
  * ```ts
4031
5051
  * // Use the new method instead:
@@ -4041,7 +5061,7 @@ var Queue = class {
4041
5061
  * @deprecated Use `player.queue.utils.findTrack()` instead.
4042
5062
  * @param predicate Function to test each track, or an object with criteria to match
4043
5063
  * @returns First matching track with its index, or null if not found
4044
- *
5064
+ *
4045
5065
  * @example
4046
5066
  * ```ts
4047
5067
  * // Use the new method instead:
@@ -4057,15 +5077,15 @@ var Queue = class {
4057
5077
  * @param sortBy Property to sort by or custom comparator function
4058
5078
  * @param order Sort order: 'asc' or 'desc' (default: 'asc')
4059
5079
  * @returns The queue instance for chaining
4060
- *
5080
+ *
4061
5081
  * @example
4062
5082
  * ```ts
4063
5083
  * // Sort by duration (shortest first)
4064
5084
  * await player.queue.sortBy("duration", "asc");
4065
- *
5085
+ *
4066
5086
  * // Sort by title alphabetically (Z-A)
4067
5087
  * await player.queue.sortBy("title", "desc");
4068
- *
5088
+ *
4069
5089
  * // Custom sorting
4070
5090
  * await player.queue.sortBy((a, b) => {
4071
5091
  * return a.info.title.localeCompare(b.info.title);
@@ -4073,7 +5093,6 @@ var Queue = class {
4073
5093
  * ```
4074
5094
  */
4075
5095
  async sortBy(sortBy, order = "asc") {
4076
- const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.toJSON() : null;
4077
5096
  if (typeof sortBy === "function") {
4078
5097
  this.tracks.sort(sortBy);
4079
5098
  } else {
@@ -4104,16 +5123,16 @@ var Queue = class {
4104
5123
  * @param sortBy Property to sort by or custom comparator function
4105
5124
  * @param order Sort order: 'asc' or 'desc' (default: 'asc')
4106
5125
  * @returns A new sorted array of tracks (does not modify the queue)
4107
- *
5126
+ *
4108
5127
  * @example
4109
5128
  * ```ts
4110
5129
  * // Get sorted copy by duration (shortest first)
4111
5130
  * const sortedTracks = player.queue.toSortedBy("duration", "asc");
4112
5131
  * // Original queue remains unchanged
4113
- *
5132
+ *
4114
5133
  * // Get sorted copy by title alphabetically (Z-A)
4115
5134
  * const sortedByTitle = player.queue.toSortedBy("title", "desc");
4116
- *
5135
+ *
4117
5136
  * // Custom sorting
4118
5137
  * const customSorted = player.queue.toSortedBy((a, b) => {
4119
5138
  * return a.info.title.localeCompare(b.info.title);
@@ -4149,12 +5168,12 @@ var Queue = class {
4149
5168
  * @param start Start index (inclusive)
4150
5169
  * @param end End index (exclusive)
4151
5170
  * @returns Array of tracks in the specified range
4152
- *
5171
+ *
4153
5172
  * @example
4154
5173
  * ```ts
4155
5174
  * // Get tracks 5-15
4156
5175
  * const tracks = player.queue.getTracks(5, 15);
4157
- *
5176
+ *
4158
5177
  * // Get first 10 tracks
4159
5178
  * const firstTen = player.queue.getTracks(0, 10);
4160
5179
  * ```
@@ -4242,7 +5261,8 @@ var Player = class {
4242
5261
  * @param LavalinkManager
4243
5262
  */
4244
5263
  constructor(options, LavalinkManager2, dontEmitPlayerCreateEvent) {
4245
- if (typeof options?.customData === "object") for (const [key, value] of Object.entries(options.customData)) this.set(key, value);
5264
+ if (typeof options?.customData === "object")
5265
+ for (const [key, value] of Object.entries(options.customData)) this.set(key, value);
4246
5266
  this.options = options;
4247
5267
  this.filterManager = new FilterManager(this);
4248
5268
  this.LavalinkManager = LavalinkManager2;
@@ -4261,14 +5281,30 @@ var Player = class {
4261
5281
  const least = this.LavalinkManager.nodeManager.leastUsedNodes();
4262
5282
  this.node = least.filter((v) => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
4263
5283
  }
4264
- if (!this.node) throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
5284
+ if (!this.node)
5285
+ throw new Error(
5286
+ "No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode"
5287
+ );
4265
5288
  if (typeof options.volume === "number" && !isNaN(options.volume)) this.volume = Number(options.volume);
4266
5289
  this.volume = Math.round(Math.max(Math.min(this.volume, 1e3), 0));
4267
- this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(
4268
- this.LavalinkManager.options.playerOptions.volumeDecrementer ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer : this.volume
4269
- ), 1e3), 0));
5290
+ this.lavalinkVolume = Math.round(
5291
+ Math.max(
5292
+ Math.min(
5293
+ Math.round(
5294
+ this.LavalinkManager.options.playerOptions.volumeDecrementer ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer : this.volume
5295
+ ),
5296
+ 1e3
5297
+ ),
5298
+ 0
5299
+ )
5300
+ );
4270
5301
  if (!dontEmitPlayerCreateEvent) this.LavalinkManager.emit("playerCreate", this);
4271
- this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
5302
+ this.queue = new Queue(
5303
+ this.guildId,
5304
+ {},
5305
+ new QueueSaver(this.LavalinkManager.options.queueOptions),
5306
+ this.LavalinkManager.options.queueOptions
5307
+ );
4272
5308
  }
4273
5309
  /**
4274
5310
  * Set custom data.
@@ -4332,20 +5368,30 @@ var Player = class {
4332
5368
  this.LavalinkManager.emit("trackError", this, this.queue.current, error);
4333
5369
  if (options && "clientTrack" in options) delete options.clientTrack;
4334
5370
  if (options && "track" in options) delete options.track;
4335
- if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0]) return this.play(options);
5371
+ if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
5372
+ return this.play(options);
4336
5373
  return this;
4337
5374
  }
4338
5375
  }
4339
- if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack) options.clientTrack.userData = {
4340
- ...typeof options?.clientTrack?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(options?.clientTrack?.requester || {}) } : {},
4341
- ...options?.clientTrack.userData,
4342
- ...options.track?.userData
4343
- };
5376
+ if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack)
5377
+ options.clientTrack.userData = {
5378
+ ...typeof options?.clientTrack?.requester === "object" ? {
5379
+ requester: this.LavalinkManager.utils.getTransformedRequester(
5380
+ options?.clientTrack?.requester || {}
5381
+ )
5382
+ } : {},
5383
+ ...options?.clientTrack.userData,
5384
+ ...options.track?.userData
5385
+ };
4344
5386
  options.track = {
4345
5387
  encoded: options.clientTrack?.encoded,
4346
5388
  requester: options.clientTrack?.requester,
4347
- userData: options.clientTrack?.userData
5389
+ userData: options.clientTrack?.userData,
5390
+ audioTrackId: options.track?.audioTrackId ?? options.clientTrack?.audioTrackId
4348
5391
  };
5392
+ if (options.track.audioTrackId && !this.node.isNodeLink()) {
5393
+ delete options.track.audioTrackId;
5394
+ }
4349
5395
  }
4350
5396
  if (options?.track?.encoded || options?.track?.identifier) {
4351
5397
  this.queue.current = options.clientTrack || null;
@@ -4353,35 +5399,48 @@ var Player = class {
4353
5399
  if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
4354
5400
  this.volume = Math.max(Math.min(options?.volume, 1e3), 0);
4355
5401
  let vol = Number(this.volume);
4356
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer) vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
5402
+ if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
5403
+ vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
4357
5404
  this.lavalinkVolume = Math.round(vol);
4358
5405
  options.volume = this.lavalinkVolume;
4359
5406
  }
4360
- const track = Object.fromEntries(Object.entries({
4361
- encoded: options.track.encoded,
4362
- identifier: options.track.identifier,
4363
- userData: {
4364
- ...typeof options?.track?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {}) } : {},
4365
- ...options.track.userData
4366
- }
4367
- }).filter((v) => typeof v[1] !== "undefined"));
5407
+ const track = Object.fromEntries(
5408
+ Object.entries({
5409
+ encoded: options.track.encoded,
5410
+ identifier: options.track.identifier,
5411
+ userData: {
5412
+ ...typeof options?.track?.requester === "object" ? {
5413
+ requester: this.LavalinkManager.utils.getTransformedRequester(
5414
+ options?.track?.requester || {}
5415
+ )
5416
+ } : {},
5417
+ ...options.track.userData
5418
+ },
5419
+ audioTrackId: options.track.audioTrackId
5420
+ }).filter((v) => typeof v[1] !== "undefined")
5421
+ );
4368
5422
  this._emitDebugEvent("PlayerPlayWithTrackReplace" /* PlayerPlayWithTrackReplace */, {
4369
5423
  state: "log",
4370
5424
  message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`,
4371
5425
  functionLayer: "Player > play()"
4372
5426
  });
5427
+ if (track.audioTrackId && !this.node.isNodeLink()) {
5428
+ delete track.audioTrackId;
5429
+ }
4373
5430
  return this.node.updatePlayer({
4374
5431
  guildId: this.guildId,
4375
5432
  noReplace: false,
4376
- playerOptions: Object.fromEntries(Object.entries({
4377
- track,
4378
- position: options.position ?? void 0,
4379
- paused: options.paused ?? void 0,
4380
- endTime: options?.endTime ?? void 0,
4381
- filters: options?.filters ?? void 0,
4382
- volume: options.volume ?? this.lavalinkVolume ?? void 0,
4383
- voice: options.voice ?? void 0
4384
- }).filter((v) => typeof v[1] !== "undefined"))
5433
+ playerOptions: Object.fromEntries(
5434
+ Object.entries({
5435
+ track,
5436
+ position: options.position ?? void 0,
5437
+ paused: options.paused ?? void 0,
5438
+ endTime: options?.endTime ?? void 0,
5439
+ filters: options?.filters ?? void 0,
5440
+ volume: options.volume ?? this.lavalinkVolume ?? void 0,
5441
+ voice: options.voice ?? void 0
5442
+ }).filter((v) => typeof v[1] !== "undefined")
5443
+ )
4385
5444
  });
4386
5445
  }
4387
5446
  if (!this.queue.current && this.queue.tracks.length) await queueTrackEnd(this);
@@ -4393,11 +5452,16 @@ var Player = class {
4393
5452
  });
4394
5453
  try {
4395
5454
  await this.queue.current.resolve(this);
4396
- if (typeof options.track?.userData === "object" && this.queue.current) this.queue.current.userData = {
4397
- ...typeof this.queue.current?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(this.queue.current?.requester || {}) } : {},
4398
- ...this.queue.current?.userData,
4399
- ...options.track?.userData
4400
- };
5455
+ if (typeof options.track?.userData === "object" && this.queue.current)
5456
+ this.queue.current.userData = {
5457
+ ...typeof this.queue.current?.requester === "object" ? {
5458
+ requester: this.LavalinkManager.utils.getTransformedRequester(
5459
+ this.queue.current?.requester || {}
5460
+ )
5461
+ } : {},
5462
+ ...this.queue.current?.userData,
5463
+ ...options.track?.userData
5464
+ };
4401
5465
  } catch (error) {
4402
5466
  this._emitDebugEvent("PlayerPlayUnresolvedTrackFailed" /* PlayerPlayUnresolvedTrackFailed */, {
4403
5467
  state: "error",
@@ -4409,7 +5473,8 @@ var Player = class {
4409
5473
  if (options && "clientTrack" in options) delete options.clientTrack;
4410
5474
  if (options && "track" in options) delete options.track;
4411
5475
  await queueTrackEnd(this, true);
4412
- if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0]) return this.play(options);
5476
+ if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
5477
+ return this.play(options);
4413
5478
  return this;
4414
5479
  }
4415
5480
  }
@@ -4417,31 +5482,46 @@ var Player = class {
4417
5482
  if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
4418
5483
  this.volume = Math.max(Math.min(options?.volume, 1e3), 0);
4419
5484
  let vol = Number(this.volume);
4420
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer) vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
5485
+ if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
5486
+ vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
4421
5487
  this.lavalinkVolume = Math.round(vol);
4422
5488
  options.volume = this.lavalinkVolume;
4423
5489
  }
4424
- const finalOptions = Object.fromEntries(Object.entries({
4425
- track: {
4426
- encoded: this.queue.current?.encoded || null,
4427
- // identifier: options.identifier,
4428
- userData: {
4429
- ...typeof this.queue.current?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(this.queue.current?.requester || {}) } : {},
4430
- ...options?.track?.userData,
4431
- ...this.queue.current?.userData
4432
- }
4433
- },
4434
- volume: this.lavalinkVolume,
4435
- position: options?.position ?? 0,
4436
- endTime: options?.endTime ?? void 0,
4437
- filters: options?.filters ?? void 0,
4438
- paused: options?.paused ?? void 0,
4439
- voice: options?.voice ?? void 0
4440
- }).filter((v) => typeof v[1] !== "undefined"));
4441
- if (typeof finalOptions.position !== "undefined" && isNaN(finalOptions.position) || typeof finalOptions.position === "number" && finalOptions.position < 0 || typeof finalOptions.position === "number" && this.queue.current.info.duration > 0 && finalOptions.position >= this.queue.current.info.duration) throw new Error("PlayerOption#position must be a positive number, less than track's duration");
4442
- if (typeof finalOptions.volume !== "undefined" && isNaN(finalOptions.volume) || typeof finalOptions.volume === "number" && finalOptions.volume < 0) throw new Error("PlayerOption#volume must be a positive number");
4443
- if (typeof finalOptions.endTime !== "undefined" && isNaN(finalOptions.endTime) || typeof finalOptions.endTime === "number" && finalOptions.endTime < 0 || typeof finalOptions.endTime === "number" && this.queue.current.info.duration > 0 && finalOptions.endTime >= this.queue.current.info.duration) throw new Error("PlayerOption#endTime must be a positive number, less than track's duration");
4444
- if (typeof finalOptions.position === "number" && typeof finalOptions.endTime === "number" && finalOptions.endTime < finalOptions.position) throw new Error("PlayerOption#endTime must be bigger than PlayerOption#position");
5490
+ const finalOptions = Object.fromEntries(
5491
+ Object.entries({
5492
+ track: {
5493
+ encoded: this.queue.current?.encoded || null,
5494
+ // identifier: options.identifier,
5495
+ userData: {
5496
+ ...typeof this.queue.current?.requester === "object" ? {
5497
+ requester: this.LavalinkManager.utils.getTransformedRequester(
5498
+ this.queue.current?.requester || {}
5499
+ )
5500
+ } : {},
5501
+ ...options?.track?.userData,
5502
+ ...this.queue.current?.userData
5503
+ },
5504
+ audioTrackId: options?.track?.audioTrackId
5505
+ },
5506
+ volume: this.lavalinkVolume,
5507
+ position: options?.position ?? 0,
5508
+ endTime: options?.endTime ?? void 0,
5509
+ filters: options?.filters ?? void 0,
5510
+ paused: options?.paused ?? void 0,
5511
+ voice: options?.voice ?? void 0
5512
+ }).filter((v) => typeof v[1] !== "undefined")
5513
+ );
5514
+ if (finalOptions.track.audioTrackId && !this.node.isNodeLink()) {
5515
+ delete finalOptions.track.audioTrackId;
5516
+ }
5517
+ if (typeof finalOptions.position !== "undefined" && isNaN(finalOptions.position) || typeof finalOptions.position === "number" && finalOptions.position < 0 || typeof finalOptions.position === "number" && this.queue.current.info.duration > 0 && finalOptions.position >= this.queue.current.info.duration)
5518
+ throw new Error("PlayerOption#position must be a positive number, less than track's duration");
5519
+ if (typeof finalOptions.volume !== "undefined" && isNaN(finalOptions.volume) || typeof finalOptions.volume === "number" && finalOptions.volume < 0)
5520
+ throw new Error("PlayerOption#volume must be a positive number");
5521
+ if (typeof finalOptions.endTime !== "undefined" && isNaN(finalOptions.endTime) || typeof finalOptions.endTime === "number" && finalOptions.endTime < 0 || typeof finalOptions.endTime === "number" && this.queue.current.info.duration > 0 && finalOptions.endTime >= this.queue.current.info.duration)
5522
+ throw new Error("PlayerOption#endTime must be a positive number, less than track's duration");
5523
+ if (typeof finalOptions.position === "number" && typeof finalOptions.endTime === "number" && finalOptions.endTime < finalOptions.position)
5524
+ throw new Error("PlayerOption#endTime must be bigger than PlayerOption#position");
4445
5525
  const now = performance.now();
4446
5526
  await this.node.updatePlayer({
4447
5527
  guildId: this.guildId,
@@ -4460,9 +5540,17 @@ var Player = class {
4460
5540
  volume = Number(volume);
4461
5541
  if (isNaN(volume)) throw new TypeError("Volume must be a number.");
4462
5542
  this.volume = Math.round(Math.max(Math.min(volume, 1e3), 0));
4463
- this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(
4464
- this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer : this.volume
4465
- ), 1e3), 0));
5543
+ this.lavalinkVolume = Math.round(
5544
+ Math.max(
5545
+ Math.min(
5546
+ Math.round(
5547
+ this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer : this.volume
5548
+ ),
5549
+ 1e3
5550
+ ),
5551
+ 0
5552
+ )
5553
+ );
4466
5554
  const now = performance.now();
4467
5555
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
4468
5556
  this._emitDebugEvent("PlayerVolumeAsFilter" /* PlayerVolumeAsFilter */, {
@@ -4470,9 +5558,15 @@ var Player = class {
4470
5558
  message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`,
4471
5559
  functionLayer: "Player > setVolume()"
4472
5560
  });
4473
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
5561
+ await this.node.updatePlayer({
5562
+ guildId: this.guildId,
5563
+ playerOptions: { filters: { volume: this.lavalinkVolume / 100 } }
5564
+ });
4474
5565
  } else {
4475
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
5566
+ await this.node.updatePlayer({
5567
+ guildId: this.guildId,
5568
+ playerOptions: { volume: this.lavalinkVolume }
5569
+ });
4476
5570
  }
4477
5571
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
4478
5572
  return this;
@@ -4556,8 +5650,10 @@ var Player = class {
4556
5650
  if (!this.queue.current) return void 0;
4557
5651
  position = Number(position);
4558
5652
  if (isNaN(position)) throw new RangeError("Position must be a number.");
4559
- if (!this.queue.current.info.isSeekable || this.queue.current.info.isStream) throw new RangeError("Current Track is not seekable / a stream");
4560
- if (position < 0 || position > this.queue.current.info.duration) position = Math.max(Math.min(position, this.queue.current.info.duration), 0);
5653
+ if (!this.queue.current.info.isSeekable || this.queue.current.info.isStream)
5654
+ throw new RangeError("Current Track is not seekable / a stream");
5655
+ if (position < 0 || position > this.queue.current.info.duration)
5656
+ position = Math.max(Math.min(position, this.queue.current.info.duration), 0);
4561
5657
  this.lastPositionChange = Date.now();
4562
5658
  this.lastPosition = position;
4563
5659
  const now = performance.now();
@@ -4570,7 +5666,8 @@ var Player = class {
4570
5666
  * @param repeatMode
4571
5667
  */
4572
5668
  async setRepeatMode(repeatMode) {
4573
- if (!["off", "track", "queue"].includes(repeatMode)) throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
5669
+ if (!["off", "track", "queue"].includes(repeatMode))
5670
+ throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
4574
5671
  this.repeatMode = repeatMode;
4575
5672
  return this;
4576
5673
  }
@@ -4579,7 +5676,8 @@ var Player = class {
4579
5676
  * @param amount provide the index of the next track to skip to
4580
5677
  */
4581
5678
  async skip(skipTo = 0, throwError = true) {
4582
- if (!this.queue.tracks.length && (throwError || typeof skipTo === "boolean" && skipTo === true)) throw new RangeError("Can't skip more than the queue size");
5679
+ if (!this.queue.tracks.length && (throwError || typeof skipTo === "boolean" && skipTo === true))
5680
+ throw new RangeError("Can't skip more than the queue size");
4583
5681
  if (typeof skipTo === "number" && skipTo > 1) {
4584
5682
  if (skipTo > this.queue.tracks.length) throw new RangeError("Can't skip more than the queue size");
4585
5683
  await this.queue.splice(0, skipTo - 1);
@@ -4587,7 +5685,10 @@ var Player = class {
4587
5685
  if (!this.playing && !this.queue.current) return this.play(), this;
4588
5686
  const now = performance.now();
4589
5687
  this.set("internal_skipped", true);
4590
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null }, paused: false } });
5688
+ await this.node.updatePlayer({
5689
+ guildId: this.guildId,
5690
+ playerOptions: { track: { encoded: null }, paused: false }
5691
+ });
4591
5692
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
4592
5693
  return this;
4593
5694
  }
@@ -4601,7 +5702,10 @@ var Player = class {
4601
5702
  if (executeAutoplay === false) this.set("internal_autoplayStopPlaying", true);
4602
5703
  else this.set("internal_autoplayStopPlaying", void 0);
4603
5704
  const now = performance.now();
4604
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null } } });
5705
+ await this.node.updatePlayer({
5706
+ guildId: this.guildId,
5707
+ playerOptions: { track: { encoded: null } }
5708
+ });
4605
5709
  this.paused = false;
4606
5710
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
4607
5711
  return this;
@@ -4611,7 +5715,8 @@ var Player = class {
4611
5715
  * @returns
4612
5716
  */
4613
5717
  async connect() {
4614
- if (!this.options.voiceChannelId) throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
5718
+ if (!this.options.voiceChannelId)
5719
+ throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
4615
5720
  await this.LavalinkManager.options.sendToShard(this.guildId, {
4616
5721
  op: 4,
4617
5722
  d: {
@@ -4625,7 +5730,8 @@ var Player = class {
4625
5730
  return this;
4626
5731
  }
4627
5732
  async changeVoiceState(data) {
4628
- if (this.options.voiceChannelId === data.voiceChannelId) throw new RangeError("New Channel can't be equal to the old Channel.");
5733
+ if (this.options.voiceChannelId === data.voiceChannelId)
5734
+ throw new RangeError("New Channel can't be equal to the old Channel.");
4629
5735
  await this.LavalinkManager.options.sendToShard(this.guildId, {
4630
5736
  op: 4,
4631
5737
  d: {
@@ -4647,7 +5753,8 @@ var Player = class {
4647
5753
  * @returns
4648
5754
  */
4649
5755
  async disconnect(force = false) {
4650
- if (!force && !this.options.voiceChannelId) throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
5756
+ if (!force && !this.options.voiceChannelId)
5757
+ throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
4651
5758
  await this.LavalinkManager.options.sendToShard(this.guildId, {
4652
5759
  op: 4,
4653
5760
  d: {
@@ -4664,7 +5771,10 @@ var Player = class {
4664
5771
  * Destroy the player and disconnect from the voice channel
4665
5772
  */
4666
5773
  async destroy(reason, disconnect = true) {
4667
- if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog) console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`);
5774
+ if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
5775
+ console.log(
5776
+ `Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`
5777
+ );
4668
5778
  if (this.get("internal_queueempty")) {
4669
5779
  clearTimeout(this.get("internal_queueempty"));
4670
5780
  this.set("internal_queueempty", void 0);
@@ -4675,7 +5785,10 @@ var Player = class {
4675
5785
  message: `Player is already destroying somewhere else..`,
4676
5786
  functionLayer: "Player > destroy()"
4677
5787
  });
4678
- if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog) console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Already destroying somewhere else..`);
5788
+ if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
5789
+ console.log(
5790
+ `Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Already destroying somewhere else..`
5791
+ );
4679
5792
  return;
4680
5793
  }
4681
5794
  this.set("internal_destroystatus", true);
@@ -4684,7 +5797,10 @@ var Player = class {
4684
5797
  await this.queue.utils.destroy();
4685
5798
  this.LavalinkManager.deletePlayer(this.guildId);
4686
5799
  await this.node.destroyPlayer(this.guildId);
4687
- if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog) console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Player got destroyed successfully`);
5800
+ if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
5801
+ console.log(
5802
+ `Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Player got destroyed successfully`
5803
+ );
4688
5804
  this.LavalinkManager.emit("playerDestroy", this, reason);
4689
5805
  return this;
4690
5806
  }
@@ -4751,23 +5867,32 @@ var Player = class {
4751
5867
  if (!updateNode) throw new Error("Could not find the new Node");
4752
5868
  if (!updateNode.connected) throw new Error("The provided Node is not active or disconnected");
4753
5869
  if (this.node.id === updateNode.id) throw new Error("Player is already on the provided Node");
4754
- if (this.get("internal_nodeChanging") === true) throw new Error("Player is already changing the node please wait");
5870
+ if (this.get("internal_nodeChanging") === true)
5871
+ throw new Error("Player is already changing the node please wait");
4755
5872
  if (checkSources) {
4756
5873
  const isDefaultSource = () => {
4757
5874
  try {
4758
- this.LavalinkManager.utils.validateSourceString(updateNode, this.LavalinkManager.options.playerOptions.defaultSearchPlatform);
5875
+ this.LavalinkManager.utils.validateSourceString(
5876
+ updateNode,
5877
+ this.LavalinkManager.options.playerOptions.defaultSearchPlatform
5878
+ );
4759
5879
  return true;
4760
5880
  } catch {
4761
5881
  return false;
4762
5882
  }
4763
5883
  };
4764
- if (!isDefaultSource()) throw new RangeError(`defaultSearchPlatform "${this.LavalinkManager.options.playerOptions.defaultSearchPlatform}" is not supported by the newNode`);
5884
+ if (!isDefaultSource())
5885
+ throw new RangeError(
5886
+ `defaultSearchPlatform "${this.LavalinkManager.options.playerOptions.defaultSearchPlatform}" is not supported by the newNode`
5887
+ );
4765
5888
  if (this.queue.current || this.queue.tracks.length) {
4766
- const trackSources = new Set([this.queue.current, ...this.queue.tracks].map((track) => track.info.sourceName));
5889
+ const trackSources = new Set(
5890
+ [this.queue.current, ...this.queue.tracks].map((track) => track.info.sourceName)
5891
+ );
4767
5892
  const missingSources = [...trackSources].filter(
4768
5893
  (source) => !updateNode.info?.sourceManagers.includes(source)
4769
5894
  );
4770
- if (this.LavalinkManager.options.autoChecks?.sourcesValidations && missingSources.length)
5895
+ if (updateNode._checkForSources && missingSources.length)
4771
5896
  throw new RangeError(`Sources missing for Node ${updateNode.id}: ${missingSources.join(", ")}`);
4772
5897
  }
4773
5898
  }
@@ -4786,7 +5911,7 @@ var Player = class {
4786
5911
  const now = performance.now();
4787
5912
  try {
4788
5913
  await this.connect();
4789
- const hasSponsorBlock = !this.LavalinkManager.options?.autoChecks?.pluginValidations || this.node.info?.plugins?.find((v) => v.name === "sponsorblock-plugin");
5914
+ const hasSponsorBlock = !this.node._checkForPlugins || this.node.info?.plugins?.find((v) => v.name === "sponsorblock-plugin");
4790
5915
  if (hasSponsorBlock) {
4791
5916
  const sponsorBlockCategories = this.get("internal_sponsorBlockCategories");
4792
5917
  if (Array.isArray(sponsorBlockCategories) && sponsorBlockCategories.length) {
@@ -4854,10 +5979,18 @@ var Player = class {
4854
5979
  */
4855
5980
  async moveNode(node) {
4856
5981
  try {
4857
- if (!node) node = Array.from(this.LavalinkManager.nodeManager.leastUsedNodes("playingPlayers")).find((n) => n.connected && n.options.id !== this.node.options.id).id;
4858
- if (!node || !this.LavalinkManager.nodeManager.nodes.get(node)) throw new RangeError("No nodes are available.");
5982
+ if (!node)
5983
+ node = Array.from(this.LavalinkManager.nodeManager.leastUsedNodes("playingPlayers")).find(
5984
+ (n) => n.connected && n.options.id !== this.node.options.id
5985
+ ).id;
5986
+ if (!node || !this.LavalinkManager.nodeManager.nodes.get(node))
5987
+ throw new RangeError("No nodes are available.");
4859
5988
  if (this.node.options.id === node) return this;
4860
- this.LavalinkManager.emit("debug", "PlayerChangeNode" /* PlayerChangeNode */, { state: "log", message: `Player.moveNode() was executed, trying to move from "${this.node.id}" to "${node}"`, functionLayer: "Player > moveNode()" });
5989
+ this.LavalinkManager.emit("debug", "PlayerChangeNode" /* PlayerChangeNode */, {
5990
+ state: "log",
5991
+ message: `Player.moveNode() was executed, trying to move from "${this.node.id}" to "${node}"`,
5992
+ functionLayer: "Player > moveNode()"
5993
+ });
4861
5994
  const updateNode = this.LavalinkManager.nodeManager.nodes.get(node);
4862
5995
  if (!updateNode) throw new RangeError("No nodes are available.");
4863
5996
  return await this.changeNode(updateNode);
@@ -4961,10 +6094,6 @@ var LavalinkManager = class extends EventEmitter2 {
4961
6094
  id: options?.client?.id,
4962
6095
  username: options?.client?.username ?? "lavalink-client"
4963
6096
  },
4964
- autoChecks: {
4965
- sourcesValidations: options?.autoChecks?.sourcesValidations ?? true,
4966
- pluginValidations: options?.autoChecks?.pluginValidations ?? true
4967
- },
4968
6097
  sendToShard: options?.sendToShard,
4969
6098
  autoMove: options?.autoMove ?? false,
4970
6099
  nodes: options?.nodes,
@@ -4973,6 +6102,7 @@ var LavalinkManager = class extends EventEmitter2 {
4973
6102
  applyVolumeAsFilter: options?.playerOptions?.applyVolumeAsFilter ?? false,
4974
6103
  clientBasedPositionUpdateInterval: options?.playerOptions?.clientBasedPositionUpdateInterval ?? 100,
4975
6104
  defaultSearchPlatform: options?.playerOptions?.defaultSearchPlatform ?? "ytsearch",
6105
+ allowCustomSources: options?.playerOptions?.allowCustomSources ?? false,
4976
6106
  onDisconnect: {
4977
6107
  destroyPlayer: options?.playerOptions?.onDisconnect?.destroyPlayer ?? true,
4978
6108
  autoReconnect: options?.playerOptions?.onDisconnect?.autoReconnect ?? false,
@@ -5023,24 +6153,36 @@ var LavalinkManager = class extends EventEmitter2 {
5023
6153
  * @param options
5024
6154
  */
5025
6155
  validateOptions(options) {
5026
- if (typeof options?.sendToShard !== "function") throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
5027
- if (options?.autoSkip && typeof options?.autoSkip !== "boolean") throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
5028
- if (options?.autoSkipOnResolveError && typeof options?.autoSkipOnResolveError !== "boolean") throw new SyntaxError("ManagerOption.autoSkipOnResolveError must be either false | true aka boolean");
5029
- if (options?.emitNewSongsOnly && typeof options?.emitNewSongsOnly !== "boolean") throw new SyntaxError("ManagerOption.emitNewSongsOnly must be either false | true aka boolean");
5030
- if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every((node) => this.utils.isNodeOptions(node))) throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
5031
- if (typeof options?.autoChecks?.sourcesValidations !== "boolean") throw new SyntaxError("ManagerOption.autoChecks.sourcesValidations must be either false | true aka boolean");
5032
- if (typeof options?.autoChecks?.pluginValidations !== "boolean") throw new SyntaxError("ManagerOption.autoChecks.pluginValidations must be either false | true aka boolean");
6156
+ if (typeof options?.sendToShard !== "function")
6157
+ throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
6158
+ if (options?.autoSkip && typeof options?.autoSkip !== "boolean")
6159
+ throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
6160
+ if (options?.autoSkipOnResolveError && typeof options?.autoSkipOnResolveError !== "boolean")
6161
+ throw new SyntaxError("ManagerOption.autoSkipOnResolveError must be either false | true aka boolean");
6162
+ if (options?.emitNewSongsOnly && typeof options?.emitNewSongsOnly !== "boolean")
6163
+ throw new SyntaxError("ManagerOption.emitNewSongsOnly must be either false | true aka boolean");
6164
+ if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every((node) => this.utils.isNodeOptions(node)))
6165
+ throw new SyntaxError(
6166
+ "ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node"
6167
+ );
5033
6168
  if (options?.queueOptions?.queueStore) {
5034
6169
  const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueStore));
5035
6170
  const requiredKeys = ["get", "set", "stringify", "parse", "delete"];
5036
- if (!requiredKeys.every((v) => keys.includes(v)) || !requiredKeys.every((v) => typeof options?.queueOptions?.queueStore[v] === "function")) throw new SyntaxError(`The provided ManagerOption.QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
6171
+ if (!requiredKeys.every((v) => keys.includes(v)) || !requiredKeys.every((v) => typeof options?.queueOptions?.queueStore[v] === "function"))
6172
+ throw new SyntaxError(
6173
+ `The provided ManagerOption.QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`
6174
+ );
5037
6175
  }
5038
6176
  if (options?.queueOptions?.queueChangesWatcher) {
5039
6177
  const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueChangesWatcher));
5040
6178
  const requiredKeys = ["tracksAdd", "tracksRemoved", "shuffled"];
5041
- if (!requiredKeys.every((v) => keys.includes(v)) || !requiredKeys.every((v) => typeof options?.queueOptions?.queueChangesWatcher[v] === "function")) throw new SyntaxError(`The provided ManagerOption.DefaultQueueChangesWatcher, does not have all required functions: ${requiredKeys.join(", ")}`);
6179
+ if (!requiredKeys.every((v) => keys.includes(v)) || !requiredKeys.every((v) => typeof options?.queueOptions?.queueChangesWatcher[v] === "function"))
6180
+ throw new SyntaxError(
6181
+ `The provided ManagerOption.DefaultQueueChangesWatcher, does not have all required functions: ${requiredKeys.join(", ")}`
6182
+ );
5042
6183
  }
5043
- if (typeof options?.queueOptions?.maxPreviousTracks !== "number" || options?.queueOptions?.maxPreviousTracks < 0) options.queueOptions.maxPreviousTracks = 25;
6184
+ if (typeof options?.queueOptions?.maxPreviousTracks !== "number" || options?.queueOptions?.maxPreviousTracks < 0)
6185
+ options.queueOptions.maxPreviousTracks = 25;
5044
6186
  }
5045
6187
  /**
5046
6188
  * Emits a debug event to the LavalinkManager
@@ -5077,6 +6219,7 @@ var LavalinkManager = class extends EventEmitter2 {
5077
6219
  * applyVolumeAsFilter: false,
5078
6220
  * clientBasedPositionUpdateInterval: 150,
5079
6221
  * defaultSearchPlatform: "ytmsearch",
6222
+ * allowCustomSources: false,
5080
6223
  * volumeDecrementer: 0.75,
5081
6224
  * //requesterTransformer: YourRequesterTransformerFunction,
5082
6225
  * onDisconnect: {
@@ -5199,7 +6342,10 @@ var LavalinkManager = class extends EventEmitter2 {
5199
6342
  const oldPlayer = this.getPlayer(guildId);
5200
6343
  if (!oldPlayer) return;
5201
6344
  if (typeof oldPlayer.voiceChannelId === "string" && oldPlayer.connected && !oldPlayer.get("internal_destroywithoutdisconnect")) {
5202
- if (!this.options?.advancedOptions?.debugOptions?.playerDestroy?.dontThrowError) throw new Error(`Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player ${safeStringify(oldPlayer.toJSON?.())}`);
6345
+ if (!this.options?.advancedOptions?.debugOptions?.playerDestroy?.dontThrowError)
6346
+ throw new Error(
6347
+ `Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player ${safeStringify(oldPlayer.toJSON?.())}`
6348
+ );
5203
6349
  this._emitDebugEvent("PlayerDeleteInsteadOfDestroy" /* PlayerDeleteInsteadOfDestroy */, {
5204
6350
  state: "warn",
5205
6351
  message: "Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player",
@@ -5239,7 +6385,8 @@ var LavalinkManager = class extends EventEmitter2 {
5239
6385
  if (this.initiated) return this;
5240
6386
  clientData = clientData ?? {};
5241
6387
  this.options.client = { ...this.options?.client, ...clientData };
5242
- if (!this.options?.client.id) throw new Error('"client.id" is not set. Pass it in Manager#init() or as a option in the constructor.');
6388
+ if (!this.options?.client.id)
6389
+ throw new Error('"client.id" is not set. Pass it in Manager#init() or as a option in the constructor.');
5243
6390
  if (typeof this.options?.client.id !== "string") throw new Error('"client.id" set is not type of "string"');
5244
6391
  let success = 0;
5245
6392
  for (const node of this.nodeManager.nodes.values()) {
@@ -5252,11 +6399,12 @@ var LavalinkManager = class extends EventEmitter2 {
5252
6399
  }
5253
6400
  }
5254
6401
  if (success > 0) this.initiated = true;
5255
- else this._emitDebugEvent("FailedToConnectToNodes" /* FailedToConnectToNodes */, {
5256
- state: "error",
5257
- message: "Failed to connect to at least 1 Node",
5258
- functionLayer: "LavalinkManager > init()"
5259
- });
6402
+ else
6403
+ this._emitDebugEvent("FailedToConnectToNodes" /* FailedToConnectToNodes */, {
6404
+ state: "error",
6405
+ message: "Failed to connect to at least 1 Node",
6406
+ functionLayer: "LavalinkManager > init()"
6407
+ });
5260
6408
  return this;
5261
6409
  }
5262
6410
  /**
@@ -5281,7 +6429,10 @@ var LavalinkManager = class extends EventEmitter2 {
5281
6429
  message: "Manager is not initated yet",
5282
6430
  functionLayer: "LavalinkManager > sendRawData()"
5283
6431
  });
5284
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, manager is not initated yet");
6432
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6433
+ console.debug(
6434
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, manager is not initated yet"
6435
+ );
5285
6436
  return;
5286
6437
  }
5287
6438
  if (!("t" in data)) {
@@ -5290,14 +6441,19 @@ var LavalinkManager = class extends EventEmitter2 {
5290
6441
  message: "No 't' in payload-data of the raw event:",
5291
6442
  functionLayer: "LavalinkManager > sendRawData()"
5292
6443
  });
5293
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 't' in payload-data of the raw event:", data);
6444
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6445
+ console.debug(
6446
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 't' in payload-data of the raw event:",
6447
+ data
6448
+ );
5294
6449
  return;
5295
6450
  }
5296
6451
  if ("CHANNEL_DELETE" === data.t) {
5297
6452
  const update = "d" in data ? data.d : data;
5298
6453
  if (!update.guild_id) return;
5299
6454
  const player = this.getPlayer(update.guild_id);
5300
- if (player && player.voiceChannelId === update.id) return void player.destroy("ChannelDeleted" /* ChannelDeleted */);
6455
+ if (player && player.voiceChannelId === update.id)
6456
+ return void player.destroy("ChannelDeleted" /* ChannelDeleted */);
5301
6457
  }
5302
6458
  if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
5303
6459
  const update = "d" in data ? data.d : data;
@@ -5307,7 +6463,11 @@ var LavalinkManager = class extends EventEmitter2 {
5307
6463
  message: `No Update data found in payload :: ${safeStringify(data, 2)}`,
5308
6464
  functionLayer: "LavalinkManager > sendRawData()"
5309
6465
  });
5310
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no update data found in payload:", data);
6466
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6467
+ console.debug(
6468
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no update data found in payload:",
6469
+ data
6470
+ );
5311
6471
  return;
5312
6472
  }
5313
6473
  if (!("token" in update) && !("session_id" in update)) {
@@ -5316,7 +6476,11 @@ var LavalinkManager = class extends EventEmitter2 {
5316
6476
  message: `No 'token' nor 'session_id' found in payload :: ${safeStringify(data, 2)}`,
5317
6477
  functionLayer: "LavalinkManager > sendRawData()"
5318
6478
  });
5319
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 'token' nor 'session_id' found in payload:", data);
6479
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6480
+ console.debug(
6481
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 'token' nor 'session_id' found in payload:",
6482
+ data
6483
+ );
5320
6484
  return;
5321
6485
  }
5322
6486
  const player = this.getPlayer(update.guild_id);
@@ -5326,7 +6490,11 @@ var LavalinkManager = class extends EventEmitter2 {
5326
6490
  message: `No Lavalink Player found via key: 'guild_id' of update-data :: ${safeStringify(update, 2)}`,
5327
6491
  functionLayer: "LavalinkManager > sendRawData()"
5328
6492
  });
5329
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, No Lavalink Player found via key: 'guild_id' of update-data:", update);
6493
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6494
+ console.debug(
6495
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, No Lavalink Player found via key: 'guild_id' of update-data:",
6496
+ update
6497
+ );
5330
6498
  return;
5331
6499
  }
5332
6500
  if (player.get("internal_destroystatus") === true) {
@@ -5335,7 +6503,10 @@ var LavalinkManager = class extends EventEmitter2 {
5335
6503
  message: `Player is in a destroying state. can't signal the voice states`,
5336
6504
  functionLayer: "LavalinkManager > sendRawData()"
5337
6505
  });
5338
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Player is in a destroying state. can't signal the voice states");
6506
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6507
+ console.debug(
6508
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Player is in a destroying state. can't signal the voice states"
6509
+ );
5339
6510
  return;
5340
6511
  }
5341
6512
  if ("token" in update) {
@@ -5347,7 +6518,15 @@ var LavalinkManager = class extends EventEmitter2 {
5347
6518
  message: `Can't send updatePlayer for voice token session - Missing sessionId :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use }, update, playerVoice: player.voice }, 2)}`,
5348
6519
  functionLayer: "LavalinkManager > sendRawData()"
5349
6520
  });
5350
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use }, update, playerVoice: player.voice });
6521
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6522
+ console.debug(
6523
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId",
6524
+ {
6525
+ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use },
6526
+ update,
6527
+ playerVoice: player.voice
6528
+ }
6529
+ );
5351
6530
  } else {
5352
6531
  await player.node.updatePlayer({
5353
6532
  guildId: player.guildId,
@@ -5364,24 +6543,44 @@ var LavalinkManager = class extends EventEmitter2 {
5364
6543
  message: `Sent updatePlayer for voice token session :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use }, update, playerVoice: player.voice }, 2)}`,
5365
6544
  functionLayer: "LavalinkManager > sendRawData()"
5366
6545
  });
5367
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use }, playerVoice: player.voice, update });
6546
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6547
+ console.debug(
6548
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session",
6549
+ {
6550
+ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use },
6551
+ playerVoice: player.voice,
6552
+ update
6553
+ }
6554
+ );
5368
6555
  }
5369
6556
  return;
5370
6557
  }
5371
6558
  if (update.user_id !== this.options?.client.id) {
5372
6559
  if (update.user_id && player.voiceChannelId) {
5373
- this.emit(update.channel_id === player.voiceChannelId ? "playerVoiceJoin" : "playerVoiceLeave", player, update.user_id);
6560
+ this.emit(
6561
+ update.channel_id === player.voiceChannelId ? "playerVoiceJoin" : "playerVoiceLeave",
6562
+ player,
6563
+ update.user_id
6564
+ );
5374
6565
  }
5375
6566
  this._emitDebugEvent("NoAudioDebug" /* NoAudioDebug */, {
5376
6567
  state: "warn",
5377
6568
  message: `voice update user is not equal to provided client id of the LavalinkManager.options.client.id :: user: "${update.user_id}" manager client id: "${this.options?.client.id}"`,
5378
6569
  functionLayer: "LavalinkManager > sendRawData()"
5379
6570
  });
5380
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, voice update user is not equal to provided client id of the manageroptions#client#id", "user:", update.user_id, "manager client id:", this.options?.client.id);
6571
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6572
+ console.debug(
6573
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, voice update user is not equal to provided client id of the manageroptions#client#id",
6574
+ "user:",
6575
+ update.user_id,
6576
+ "manager client id:",
6577
+ this.options?.client.id
6578
+ );
5381
6579
  return;
5382
6580
  }
5383
6581
  if (update.channel_id) {
5384
- if (player.voiceChannelId !== update.channel_id) this.emit("playerMove", player, player.voiceChannelId, update.channel_id);
6582
+ if (player.voiceChannelId !== update.channel_id)
6583
+ this.emit("playerMove", player, player.voiceChannelId, update.channel_id);
5385
6584
  player.voice.sessionId = update.session_id || player.voice.sessionId;
5386
6585
  if (!player.voice.sessionId) {
5387
6586
  this._emitDebugEvent("NoAudioDebug" /* NoAudioDebug */, {
@@ -5389,7 +6588,10 @@ var LavalinkManager = class extends EventEmitter2 {
5389
6588
  message: `Function to assing sessionId provided, but no found in Payload: ${safeStringify({ update, playerVoice: player.voice }, 2)}`,
5390
6589
  functionLayer: "LavalinkManager > sendRawData()"
5391
6590
  });
5392
- if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug(`Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Function to assing sessionId provided, but no found in Payload: ${safeStringify(update, 2)}`);
6591
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6592
+ console.debug(
6593
+ `Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Function to assing sessionId provided, but no found in Payload: ${safeStringify(update, 2)}`
6594
+ );
5393
6595
  }
5394
6596
  player.voiceChannelId = update.channel_id;
5395
6597
  player.options.voiceChannelId = update.channel_id;
@@ -5403,15 +6605,13 @@ var LavalinkManager = class extends EventEmitter2 {
5403
6605
  player.voiceState.serverDeaf = update.deaf ?? player.voiceState?.serverDeaf;
5404
6606
  player.voiceState.serverMute = update.mute ?? player.voiceState?.serverMute;
5405
6607
  player.voiceState.suppress = update.suppress ?? player.voiceState?.suppress;
5406
- if (selfMuteChanged || serverMuteChanged) this.emit("playerMuteChange", player, player.voiceState.selfMute, player.voiceState.serverMute);
5407
- if (selfDeafChanged || serverDeafChanged) this.emit("playerDeafChange", player, player.voiceState.selfDeaf, player.voiceState.serverDeaf);
6608
+ if (selfMuteChanged || serverMuteChanged)
6609
+ this.emit("playerMuteChange", player, player.voiceState.selfMute, player.voiceState.serverMute);
6610
+ if (selfDeafChanged || serverDeafChanged)
6611
+ this.emit("playerDeafChange", player, player.voiceState.selfDeaf, player.voiceState.serverDeaf);
5408
6612
  if (suppressChange) this.emit("playerSuppressChange", player, player.voiceState.suppress);
5409
6613
  } else {
5410
- const {
5411
- autoReconnectOnlyWithTracks,
5412
- destroyPlayer,
5413
- autoReconnect
5414
- } = this.options?.playerOptions?.onDisconnect ?? {};
6614
+ const { autoReconnectOnlyWithTracks, destroyPlayer, autoReconnect } = this.options?.playerOptions?.onDisconnect ?? {};
5415
6615
  if (destroyPlayer === true) {
5416
6616
  return void await player.destroy("Disconnected" /* Disconnected */);
5417
6617
  }
@@ -5429,7 +6629,11 @@ var LavalinkManager = class extends EventEmitter2 {
5429
6629
  this.emit("playerReconnect", player, player.voiceChannelId);
5430
6630
  }
5431
6631
  if (player.queue.current) {
5432
- return void await player.play({ position: previousPosition, paused: previousPaused, clientTrack: player.queue.current });
6632
+ return void await player.play({
6633
+ position: previousPosition,
6634
+ paused: previousPaused,
6635
+ clientTrack: player.queue.current
6636
+ });
5433
6637
  }
5434
6638
  if (player.queue.tracks.length) {
5435
6639
  return void await player.play({ paused: previousPaused });
@@ -5466,12 +6670,15 @@ export {
5466
6670
  LavalinkPlugins,
5467
6671
  ManagerUtils,
5468
6672
  MiniMap,
6673
+ NodeLinkExclusiveEvents,
6674
+ NodeLinkNode,
5469
6675
  NodeManager,
5470
6676
  NodeSymbol,
5471
6677
  Player,
5472
6678
  Queue,
5473
6679
  QueueSaver,
5474
6680
  QueueSymbol,
6681
+ RecommendationsStrings,
5475
6682
  ReconnectionState,
5476
6683
  SourceLinksRegexes,
5477
6684
  TrackSymbol,