lavalink-client 2.7.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ __export(index_exports, {
47
47
  Queue: () => Queue,
48
48
  QueueSaver: () => QueueSaver,
49
49
  QueueSymbol: () => QueueSymbol,
50
+ ReconnectionState: () => ReconnectionState,
50
51
  SourceLinksRegexes: () => SourceLinksRegexes,
51
52
  TrackSymbol: () => TrackSymbol,
52
53
  UnresolvedTrackSymbol: () => UnresolvedTrackSymbol,
@@ -367,6 +368,15 @@ var import_events = require("events");
367
368
  var import_path = require("path");
368
369
  var import_ws = __toESM(require("ws"));
369
370
 
371
+ // src/structures/Types/Node.ts
372
+ var ReconnectionState = /* @__PURE__ */ ((ReconnectionState2) => {
373
+ ReconnectionState2["IDLE"] = "IDLE";
374
+ ReconnectionState2["RECONNECTING"] = "RECONNECTING";
375
+ ReconnectionState2["PENDING"] = "PENDING";
376
+ ReconnectionState2["DESTROYING"] = "DESTROYING";
377
+ return ReconnectionState2;
378
+ })(ReconnectionState || {});
379
+
370
380
  // src/structures/Utils.ts
371
381
  var import_node_url = require("url");
372
382
  var import_types = require("util/types");
@@ -1070,12 +1080,14 @@ var LavalinkNode = class {
1070
1080
  resuming = { enabled: true, timeout: null };
1071
1081
  /** Actual Lavalink Information of the Node */
1072
1082
  info = null;
1083
+ /** current state of the Reconnections */
1084
+ reconnectionState = "IDLE" /* IDLE */;
1073
1085
  /** The Node Manager of this Node */
1074
1086
  NodeManager = null;
1075
1087
  /** The Reconnection Timeout */
1076
1088
  reconnectTimeout = void 0;
1077
- /** The Reconnection Attempt counter */
1078
- reconnectAttempts = 1;
1089
+ /** The Reconnection Attempt counter (array of datetimes when it tried it.) */
1090
+ reconnectAttempts = [];
1079
1091
  /** The Socket of the Lavalink */
1080
1092
  socket = null;
1081
1093
  /** Version of what the Lavalink Server should be */
@@ -1098,6 +1110,7 @@ var LavalinkNode = class {
1098
1110
  secure: false,
1099
1111
  retryAmount: 5,
1100
1112
  retryDelay: 1e4,
1113
+ retryTimespan: -1,
1101
1114
  requestSignalTimeoutMS: 1e4,
1102
1115
  heartBeatInterval: 3e4,
1103
1116
  closeOnError: true,
@@ -1354,6 +1367,7 @@ var LavalinkNode = class {
1354
1367
  functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat()"
1355
1368
  });
1356
1369
  }
1370
+ this.resetAckTimeouts(false, true);
1357
1371
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
1358
1372
  this.pingTimeout = setTimeout(() => {
1359
1373
  this.pingTimeout = null;
@@ -1450,13 +1464,11 @@ var LavalinkNode = class {
1450
1464
  this.socket?.close(1e3, "Node-Destroy");
1451
1465
  this.socket?.removeAllListeners();
1452
1466
  this.socket = null;
1453
- this.reconnectAttempts = 1;
1454
- clearTimeout(this.reconnectTimeout);
1467
+ this.resetReconnectionAttempts();
1455
1468
  if (deleteNode) {
1456
1469
  this.NodeManager.emit("destroy", this, destroyReason);
1457
1470
  this.NodeManager.nodes.delete(this.id);
1458
- clearInterval(this.heartBeatInterval);
1459
- clearTimeout(this.pingTimeout);
1471
+ this.resetAckTimeouts(true, true);
1460
1472
  } else {
1461
1473
  this.NodeManager.emit("disconnect", this, { code: 1e3, reason: destroyReason });
1462
1474
  }
@@ -1465,13 +1477,11 @@ var LavalinkNode = class {
1465
1477
  this.socket?.close(1e3, "Node-Destroy");
1466
1478
  this.socket?.removeAllListeners();
1467
1479
  this.socket = null;
1468
- this.reconnectAttempts = 1;
1469
- clearTimeout(this.reconnectTimeout);
1480
+ this.resetReconnectionAttempts();
1470
1481
  if (deleteNode) {
1471
1482
  this.NodeManager.emit("destroy", this, destroyReason);
1472
1483
  this.NodeManager.nodes.delete(this.id);
1473
- clearInterval(this.heartBeatInterval);
1474
- clearTimeout(this.pingTimeout);
1484
+ this.resetAckTimeouts(true, true);
1475
1485
  } else {
1476
1486
  this.NodeManager.emit("disconnect", this, { code: 1e3, reason: destroyReason });
1477
1487
  }
@@ -1495,8 +1505,7 @@ var LavalinkNode = class {
1495
1505
  this.socket?.close(1e3, "Node-Disconnect");
1496
1506
  this.socket?.removeAllListeners();
1497
1507
  this.socket = null;
1498
- this.reconnectAttempts = 1;
1499
- clearTimeout(this.reconnectTimeout);
1508
+ this.resetReconnectionAttempts();
1500
1509
  this.NodeManager.emit("disconnect", this, { code: 1e3, reason: disconnectReason });
1501
1510
  }
1502
1511
  /**
@@ -1866,46 +1875,91 @@ var LavalinkNode = class {
1866
1875
  get restAddress() {
1867
1876
  return `http${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}`;
1868
1877
  }
1878
+ /**
1879
+ * If already trying to reconnect or pending, return
1880
+ */
1881
+ get isNodeReconnecting() {
1882
+ return this.reconnectionState !== "IDLE" /* IDLE */;
1883
+ }
1869
1884
  /**
1870
1885
  * Reconnect to the lavalink node
1871
- * @param instaReconnect @default false wether to instantly try to reconnect
1886
+ * @param force @default false Wether to instantly try to reconnect (force it)
1872
1887
  * @returns void
1873
1888
  *
1874
1889
  * @example
1875
1890
  * ```ts
1876
- * await player.node.reconnect();
1891
+ * await player.node.reconnect(true); //true forcefully trys the reconnect
1877
1892
  * ```
1878
1893
  */
1879
- reconnect(instaReconnect = false) {
1894
+ reconnect(force = false) {
1895
+ if (this.isNodeReconnecting) {
1896
+ return;
1897
+ }
1898
+ this.reconnectionState = "PENDING" /* PENDING */;
1880
1899
  this.NodeManager.emit("reconnectinprogress", this);
1881
- if (instaReconnect) {
1882
- if (this.reconnectAttempts >= this.options.retryAmount) {
1883
- const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
1884
- this.NodeManager.emit("error", this, error);
1885
- return this.destroy("NodeReconnectFail" /* NodeReconnectFail */);
1886
- }
1887
- this.NodeManager.emit("reconnecting", this);
1888
- this.connect();
1889
- this.reconnectAttempts++;
1900
+ if (force) {
1901
+ this.executeReconnect();
1890
1902
  return;
1891
1903
  }
1904
+ if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout);
1892
1905
  this.reconnectTimeout = setTimeout(() => {
1893
1906
  this.reconnectTimeout = null;
1894
- if (this.reconnectAttempts >= this.options.retryAmount) {
1895
- const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
1896
- this.NodeManager.emit("error", this, error);
1897
- return this.destroy("NodeReconnectFail" /* NodeReconnectFail */);
1898
- }
1899
- this.NodeManager.emit("reconnecting", this);
1900
- this.connect();
1901
- this.reconnectAttempts++;
1907
+ this.executeReconnect();
1902
1908
  }, this.options.retryDelay || 1e3);
1903
1909
  }
1910
+ get reconnectionAttemptCount() {
1911
+ const maxAllowedTimestan = this.options.retryTimespan || -1;
1912
+ if (maxAllowedTimestan <= 0) return this.reconnectAttempts.length;
1913
+ return this.reconnectAttempts.filter((timestamp) => Date.now() - timestamp <= maxAllowedTimestan).length;
1914
+ }
1915
+ /**
1916
+ * Private Utility function to execute the reconnection
1917
+ */
1918
+ executeReconnect() {
1919
+ if (this.reconnectionAttemptCount >= this.options.retryAmount) {
1920
+ const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
1921
+ this.reconnectionState = "DESTROYING" /* DESTROYING */;
1922
+ this.NodeManager.emit("error", this, error);
1923
+ this.destroy("NodeReconnectFail" /* NodeReconnectFail */);
1924
+ return;
1925
+ }
1926
+ this.reconnectAttempts.push(Date.now());
1927
+ this.reconnectionState = "RECONNECTING" /* RECONNECTING */;
1928
+ this.NodeManager.emit("reconnecting", this);
1929
+ this.connect();
1930
+ }
1931
+ /**
1932
+ * Private function to reset the reconnection attempts
1933
+ * @returns
1934
+ */
1935
+ resetReconnectionAttempts() {
1936
+ this.reconnectionState = "IDLE" /* IDLE */;
1937
+ this.reconnectAttempts = [];
1938
+ clearTimeout(this.reconnectTimeout);
1939
+ this.reconnectTimeout = null;
1940
+ return;
1941
+ }
1942
+ /**
1943
+ * Private function to reset timeouts/intervals for heartbeating/pinging
1944
+ * @param heartbeat
1945
+ * @param ping
1946
+ * @returns
1947
+ */
1948
+ resetAckTimeouts(heartbeat = true, ping = true) {
1949
+ if (ping) {
1950
+ if (this.pingTimeout) clearTimeout(this.pingTimeout);
1951
+ this.pingTimeout = null;
1952
+ }
1953
+ if (heartbeat) {
1954
+ if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
1955
+ this.heartBeatInterval = null;
1956
+ }
1957
+ return;
1958
+ }
1904
1959
  /** @private util function for handling opening events from websocket */
1905
1960
  async open() {
1906
1961
  this.isAlive = true;
1907
- this.reconnectAttempts = 1;
1908
- if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout);
1962
+ this.resetReconnectionAttempts();
1909
1963
  if (this.options.enablePingOnStatsCheck) this.heartBeat();
1910
1964
  if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
1911
1965
  if (this.options.heartBeatInterval > 0) {
@@ -1930,7 +1984,7 @@ var LavalinkNode = class {
1930
1984
  }
1931
1985
  /** @private util function for handling closing events from websocket */
1932
1986
  close(code, reason) {
1933
- if (this.pingTimeout) clearTimeout(this.pingTimeout);
1987
+ this.resetAckTimeouts(true, true);
1934
1988
  try {
1935
1989
  if (this.socket) {
1936
1990
  this.socket.removeAllListeners();
@@ -1946,7 +2000,6 @@ var LavalinkNode = class {
1946
2000
  }
1947
2001
  }
1948
2002
  this.isAlive = false;
1949
- if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
1950
2003
  if (code === 1006 && !reason) reason = "Socket got terminated due to no ping connection";
1951
2004
  if (code === 1e3 && reason === "Node-Disconnect") return;
1952
2005
  this.NodeManager.emit("disconnect", this, { code, reason });
@@ -1968,6 +2021,7 @@ var LavalinkNode = class {
1968
2021
  error(error) {
1969
2022
  if (!error) return;
1970
2023
  this.NodeManager.emit("error", this, error);
2024
+ this.reconnect();
1971
2025
  if (this.options.closeOnError) {
1972
2026
  if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
1973
2027
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
@@ -2031,6 +2085,7 @@ var LavalinkNode = class {
2031
2085
  this.handleEvent(payload);
2032
2086
  break;
2033
2087
  case "ready":
2088
+ this.resetReconnectionAttempts();
2034
2089
  this.sessionId = payload.sessionId;
2035
2090
  this.resuming.enabled = payload.resumed;
2036
2091
  if (payload.resumed === true) {
@@ -2400,10 +2455,7 @@ var LavalinkNode = class {
2400
2455
  });
2401
2456
  }
2402
2457
  this.NodeManager.LavalinkManager.emit("playerQueueEmptyStart", player, this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs);
2403
- if (player.get("internal_queueempty")) {
2404
- clearTimeout(player.get("internal_queueempty"));
2405
- player.set("internal_queueempty", void 0);
2406
- }
2458
+ if (player.get("internal_queueempty")) clearTimeout(player.get("internal_queueempty"));
2407
2459
  player.set("internal_queueempty", setTimeout(() => {
2408
2460
  player.set("internal_queueempty", void 0);
2409
2461
  if (player.queue.current) {
@@ -2709,7 +2761,13 @@ var bandCampSearch = async (player, query, requestUser) => {
2709
2761
  "Cookie": "$Version=1"
2710
2762
  }
2711
2763
  });
2712
- const json = await data.json();
2764
+ if (!data.ok) throw new Error(`Bandcamp Error: ${data.statusText}`);
2765
+ let json = null;
2766
+ try {
2767
+ json = await data.json();
2768
+ } catch {
2769
+ throw new Error("Invalid JSON response from Bandcamp");
2770
+ }
2713
2771
  tracks = json?.results?.filter((x) => !!x && typeof x === "object" && "type" in x && x.type === "t").map?.((item) => player.LavalinkManager.utils.buildUnresolvedTrack({
2714
2772
  uri: item.url || item.uri,
2715
2773
  artworkUrl: item.img,
@@ -2924,15 +2982,15 @@ var FilterManager = class {
2924
2982
  const lavalinkFilterData = this.data.pluginFilters?.["lavalink-filter-plugin"] || { echo: { decay: this.data.pluginFilters?.echo?.decay && !this.data.pluginFilters?.echo?.echoLength ? this.data.pluginFilters.echo.decay : 0, delay: this.data.pluginFilters?.echo?.delay || 0 }, reverb: { gains: [], delays: [], ...this.data.pluginFilters.reverb } };
2925
2983
  this.filters.lavalinkFilterPlugin.echo = lavalinkFilterData.echo.decay !== 0 || lavalinkFilterData.echo.delay !== 0;
2926
2984
  this.filters.lavalinkFilterPlugin.reverb = lavalinkFilterData.reverb?.delays?.length !== 0 || lavalinkFilterData.reverb?.gains?.length !== 0;
2927
- this.filters.lavalinkLavaDspxPlugin.highPass = Object.values(this.data.pluginFilters["high-pass"] || {}).length > 0;
2928
- this.filters.lavalinkLavaDspxPlugin.lowPass = Object.values(this.data.pluginFilters["low-pass"] || {}).length > 0;
2929
- this.filters.lavalinkLavaDspxPlugin.normalization = Object.values(this.data.pluginFilters.normalization || {}).length > 0;
2930
- this.filters.lavalinkLavaDspxPlugin.echo = Object.values(this.data.pluginFilters.echo || {}).length > 0 && typeof this.data.pluginFilters?.echo?.delay === "undefined";
2931
- this.filters.lowPass = this.data.lowPass.smoothing !== 0;
2932
- this.filters.karaoke = Object.values(this.data.karaoke).some((v) => v !== 0);
2985
+ this.filters.lavalinkLavaDspxPlugin.highPass = Object.values(this.data.pluginFilters?.["high-pass"] || {}).length > 0;
2986
+ this.filters.lavalinkLavaDspxPlugin.lowPass = Object.values(this.data.pluginFilters?.["low-pass"] || {}).length > 0;
2987
+ this.filters.lavalinkLavaDspxPlugin.normalization = Object.values(this.data.pluginFilters?.normalization || {}).length > 0;
2988
+ this.filters.lavalinkLavaDspxPlugin.echo = Object.values(this.data.pluginFilters?.echo || {}).length > 0 && typeof this.data.pluginFilters?.echo?.delay === "undefined";
2989
+ this.filters.lowPass = this.privateNot0(this.data.lowPass?.smoothing);
2990
+ this.filters.karaoke = Object.values(this.data.karaoke ?? {}).some((v) => v !== 0);
2933
2991
  if ((this.filters.nightcore || this.filters.vaporwave) && oldFilterTimescale) {
2934
- if (oldFilterTimescale.pitch !== this.data.timescale.pitch || oldFilterTimescale.rate !== this.data.timescale.rate || oldFilterTimescale.speed !== this.data.timescale.speed) {
2935
- this.filters.custom = Object.values(this.data.timescale).some((v) => v !== 1);
2992
+ if (oldFilterTimescale.pitch !== this.data.timescale?.pitch || oldFilterTimescale.rate !== this.data.timescale?.rate || oldFilterTimescale.speed !== this.data.timescale?.speed) {
2993
+ this.filters.custom = Object.values(this.data.timescale || {}).some((v) => v !== 1);
2936
2994
  this.filters.nightcore = false;
2937
2995
  this.filters.vaporwave = false;
2938
2996
  }
@@ -3745,8 +3803,11 @@ var Queue = class {
3745
3803
  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());
3746
3804
  } catch {
3747
3805
  }
3748
- let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))) : this.tracks.splice(index, amount);
3749
- spliced = Array.isArray(spliced) ? spliced : [spliced];
3806
+ const spliced = TrackOrTracks ? this.tracks.splice(
3807
+ index,
3808
+ amount,
3809
+ ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).flat(2).filter((v) => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))
3810
+ ) : this.tracks.splice(index, amount);
3750
3811
  if (typeof this.queueChanges?.tracksRemoved === "function") try {
3751
3812
  this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
3752
3813
  } catch {
@@ -4311,6 +4372,7 @@ var Player = class {
4311
4372
  else this.set("internal_autoplayStopPlaying", void 0);
4312
4373
  const now = performance.now();
4313
4374
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null } } });
4375
+ this.paused = false;
4314
4376
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
4315
4377
  return this;
4316
4378
  }
@@ -5113,6 +5175,7 @@ var LavalinkManager = class extends import_events2.EventEmitter {
5113
5175
  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)}`);
5114
5176
  }
5115
5177
  player.voiceChannelId = update.channel_id;
5178
+ player.options.voiceChannelId = update.channel_id;
5116
5179
  const selfMuteChanged = typeof update.self_mute === "boolean" && player.voiceState.selfMute !== update.self_mute;
5117
5180
  const serverMuteChanged = typeof update.mute === "boolean" && player.voiceState.serverMute !== update.mute;
5118
5181
  const selfDeafChanged = typeof update.self_deaf === "boolean" && player.voiceState.selfDeaf !== update.self_deaf;
@@ -5155,11 +5218,13 @@ var LavalinkManager = class extends import_events2.EventEmitter {
5155
5218
  if (player.queue.tracks.length) {
5156
5219
  return void await player.play({ paused: previousPaused });
5157
5220
  }
5158
- this.emit("debug", "PlayerAutoReconnect" /* PlayerAutoReconnect */, {
5159
- state: "log",
5160
- message: `Auto reconnected, but nothing to play`,
5161
- functionLayer: "LavalinkManager > sendRawData()"
5162
- });
5221
+ if (this.options?.advancedOptions?.enableDebugEvents) {
5222
+ this.emit("debug", "PlayerAutoReconnect" /* PlayerAutoReconnect */, {
5223
+ state: "log",
5224
+ message: `Auto reconnected, but nothing to play`,
5225
+ functionLayer: "LavalinkManager > sendRawData()"
5226
+ });
5227
+ }
5163
5228
  return;
5164
5229
  } catch (e) {
5165
5230
  console.error(e);
@@ -5194,6 +5259,7 @@ var LavalinkManager = class extends import_events2.EventEmitter {
5194
5259
  Queue,
5195
5260
  QueueSaver,
5196
5261
  QueueSymbol,
5262
+ ReconnectionState,
5197
5263
  SourceLinksRegexes,
5198
5264
  TrackSymbol,
5199
5265
  UnresolvedTrackSymbol,