lavalink-client 2.9.1 → 2.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,7 +44,7 @@
44
44
 
45
45
  ## 📦 Installation
46
46
 
47
- **Latest Stable Version: `v2.5.x`**
47
+ **Latest Stable Version: `v2.9.x`**
48
48
 
49
49
  <details>
50
50
  <summary><strong>👉 via NPM</strong></summary>
@@ -359,6 +359,7 @@ This client powers various Discord bots:
359
359
  - [All Time Bot](https://top.gg/bot/1163027457671180418) (@PeterGamez)
360
360
  - [BeatDock](https://github.com/lazaroagomez/BeatDock) (@lazaroagomez)
361
361
  - [Nazha](https://top.gg/bot/1124681788070055967) (@Nazha-Team)
362
+ - [Arii Music](https://arimusic.me/) (@friston_ae)
362
363
 
363
364
  ---
364
365
 
@@ -1,5 +1,69 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/index.ts
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ DebugEvents: () => DebugEvents,
33
+ DefaultQueueStore: () => DefaultQueueStore,
34
+ DefaultSources: () => DefaultSources,
35
+ DestroyReasons: () => DestroyReasons,
36
+ DisconnectReasons: () => DisconnectReasons,
37
+ EQList: () => EQList,
38
+ FilterManager: () => FilterManager,
39
+ LavalinkManager: () => LavalinkManager,
40
+ LavalinkNode: () => LavalinkNode,
41
+ LavalinkPlugins: () => LavalinkPlugins,
42
+ ManagerUtils: () => ManagerUtils,
43
+ MiniMap: () => MiniMap,
44
+ NodeLinkExclusiveEvents: () => NodeLinkExclusiveEvents,
45
+ NodeLinkNode: () => NodeLinkNode,
46
+ NodeManager: () => NodeManager,
47
+ NodeSymbol: () => NodeSymbol,
48
+ Player: () => Player,
49
+ Queue: () => Queue,
50
+ QueueSaver: () => QueueSaver,
51
+ QueueSymbol: () => QueueSymbol,
52
+ RecommendationsStrings: () => RecommendationsStrings,
53
+ ReconnectionState: () => ReconnectionState,
54
+ SourceLinksRegexes: () => SourceLinksRegexes,
55
+ TrackSymbol: () => TrackSymbol,
56
+ UnresolvedTrackSymbol: () => UnresolvedTrackSymbol,
57
+ audioOutputsData: () => audioOutputsData,
58
+ parseLavalinkConnUrl: () => parseLavalinkConnUrl,
59
+ queueTrackEnd: () => queueTrackEnd,
60
+ safeStringify: () => safeStringify,
61
+ validSponsorBlocks: () => validSponsorBlocks
62
+ });
63
+ module.exports = __toCommonJS(index_exports);
64
+
1
65
  // src/structures/LavalinkManager.ts
2
- import { EventEmitter as EventEmitter2 } from "events";
66
+ var import_node_events2 = require("events");
3
67
 
4
68
  // src/structures/Constants.ts
5
69
  var DebugEvents = /* @__PURE__ */ ((DebugEvents2) => {
@@ -340,11 +404,11 @@ var NodeLinkExclusiveEvents = [
340
404
  ];
341
405
 
342
406
  // src/structures/NodeManager.ts
343
- import { EventEmitter } from "events";
407
+ var import_node_events = require("events");
344
408
 
345
409
  // src/structures/Node.ts
346
- import { isAbsolute } from "path";
347
- import WebSocket from "ws";
410
+ var import_node_path = require("path");
411
+ var import_ws = __toESM(require("ws"), 1);
348
412
 
349
413
  // src/structures/Types/Node.ts
350
414
  var ReconnectionState = /* @__PURE__ */ ((ReconnectionState2) => {
@@ -356,8 +420,8 @@ var ReconnectionState = /* @__PURE__ */ ((ReconnectionState2) => {
356
420
  })(ReconnectionState || {});
357
421
 
358
422
  // src/structures/Utils.ts
359
- import { URL as URL2 } from "url";
360
- import { isRegExp } from "util/types";
423
+ var import_node_url = require("url");
424
+ var import_types = require("util/types");
361
425
 
362
426
  // src/structures/LavalinkManagerStatics.ts
363
427
  var DefaultSources = {
@@ -527,7 +591,7 @@ var escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
527
591
  function parseLavalinkConnUrl(connectionUrl) {
528
592
  if (!connectionUrl.startsWith("lavalink://"))
529
593
  throw new Error(`ConnectionUrl (${connectionUrl}) must start with 'lavalink://'`);
530
- const parsed = new URL2(connectionUrl);
594
+ const parsed = new import_node_url.URL(connectionUrl);
531
595
  return {
532
596
  authorization: parsed.password,
533
597
  id: parsed.username,
@@ -792,7 +856,7 @@ var ManagerUtils = class {
792
856
  });
793
857
  }
794
858
  if (this.LavalinkManager.options?.linksBlacklist.some(
795
- (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString)
859
+ (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || (0, import_types.isRegExp)(v) && v.test(queryString)
796
860
  )) {
797
861
  throw new Error(`Query string contains a link / word which is blacklisted.`);
798
862
  }
@@ -809,7 +873,7 @@ var ManagerUtils = class {
809
873
  });
810
874
  }
811
875
  if (!this.LavalinkManager.options?.linksWhitelist.some(
812
- (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString)
876
+ (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || (0, import_types.isRegExp)(v) && v.test(queryString)
813
877
  )) {
814
878
  throw new Error(`Query string contains a link / word which isn't whitelisted.`);
815
879
  }
@@ -1285,7 +1349,7 @@ var LavalinkNode = class _LavalinkNode {
1285
1349
  * ```
1286
1350
  */
1287
1351
  get connected() {
1288
- return this.socket && this.socket.readyState === WebSocket.OPEN;
1352
+ return this.socket && this.socket.readyState === import_ws.default.OPEN;
1289
1353
  }
1290
1354
  /**
1291
1355
  * Returns the current ConnectionStatus
@@ -1605,7 +1669,7 @@ var LavalinkNode = class _LavalinkNode {
1605
1669
  headers["Session-Id"] = this.options.sessionId || sessionId;
1606
1670
  this.sessionId = this.options.sessionId || sessionId;
1607
1671
  }
1608
- this.socket = new WebSocket(
1672
+ this.socket = new import_ws.default(
1609
1673
  `ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`,
1610
1674
  { headers }
1611
1675
  );
@@ -2517,12 +2581,13 @@ var LavalinkNode = class _LavalinkNode {
2517
2581
  if (!error) return;
2518
2582
  this.NodeManager.emit("error", this, error);
2519
2583
  this.reconnectionState = "IDLE" /* IDLE */;
2520
- this.reconnect();
2521
2584
  if (this.options.closeOnError) {
2522
2585
  if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
2523
2586
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
2524
2587
  this.socket?.close(500, "Node-Error - Force Reconnect");
2588
+ return;
2525
2589
  }
2590
+ this.reconnect();
2526
2591
  }
2527
2592
  /** @private util function for handling message events from websocket */
2528
2593
  async message(d) {
@@ -2558,7 +2623,7 @@ var LavalinkNode = class _LavalinkNode {
2558
2623
  player.connected = payload.state.connected;
2559
2624
  player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
2560
2625
  if (!player.createdTimeStamp && payload.state.time) player.createdTimeStamp = payload.state.time;
2561
- if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 6e5) || player.queue.current?.info?.uri && isAbsolute(player.queue.current?.info?.uri))) {
2626
+ if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 6e5) || player.queue.current?.info?.uri && (0, import_node_path.isAbsolute)(player.queue.current?.info?.uri))) {
2562
2627
  player.filterManager.filterUpdatedState = false;
2563
2628
  this._emitDebugEvent("PlayerUpdateFilterFixApply" /* PlayerUpdateFilterFixApply */, {
2564
2629
  state: "log",
@@ -2746,7 +2811,7 @@ var LavalinkNode = class _LavalinkNode {
2746
2811
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2747
2812
  );
2748
2813
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2749
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2814
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2750
2815
  this._emitDebugEvent("TrackStuckMaxTracksErroredPerTime" /* TrackStuckMaxTracksErroredPerTime */, {
2751
2816
  state: "log",
2752
2817
  message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -2784,7 +2849,7 @@ var LavalinkNode = class _LavalinkNode {
2784
2849
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2785
2850
  );
2786
2851
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2787
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2852
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2788
2853
  this._emitDebugEvent("TrackErrorMaxTracksErroredPerTime" /* TrackErrorMaxTracksErroredPerTime */, {
2789
2854
  state: "log",
2790
2855
  message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -3363,7 +3428,7 @@ var NodeLinkNode = class extends LavalinkNode {
3363
3428
  LavalinkNode._NodeLinkClass = NodeLinkNode;
3364
3429
 
3365
3430
  // src/structures/NodeManager.ts
3366
- var NodeManager = class extends EventEmitter {
3431
+ var NodeManager = class extends import_node_events.EventEmitter {
3367
3432
  /**
3368
3433
  * Emit an event
3369
3434
  * @param event The event to emit
@@ -3844,6 +3909,7 @@ var FilterManager = class {
3844
3909
  }
3845
3910
  const now = performance.now();
3846
3911
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
3912
+ this.player.triggerPlayerClientUpdate();
3847
3913
  await this.player.node.updatePlayer({
3848
3914
  guildId: this.player.guildId,
3849
3915
  playerOptions: {
@@ -3938,7 +4004,7 @@ var FilterManager = class {
3938
4004
  this.filters.tremolo = false;
3939
4005
  this.filters.vibrato = false;
3940
4006
  this.filters.karaoke = false;
3941
- this.filters.karaoke = false;
4007
+ this.filters.vaporwave = false;
3942
4008
  this.filters.volume = false;
3943
4009
  this.filters.nodeLinkEcho = false;
3944
4010
  this.filters.nodeLinkChorus = false;
@@ -4019,7 +4085,7 @@ var FilterManager = class {
4019
4085
  this.data = this.data ?? {};
4020
4086
  this.filters.nightcore = false;
4021
4087
  this.filters.vaporwave = false;
4022
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, speed };
4088
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, speed };
4023
4089
  this.isCustomFilterActive();
4024
4090
  await this.applyPlayerFilters();
4025
4091
  return this;
@@ -4041,7 +4107,7 @@ var FilterManager = class {
4041
4107
  this.data = this.data ?? {};
4042
4108
  this.filters.nightcore = false;
4043
4109
  this.filters.vaporwave = false;
4044
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, pitch };
4110
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, pitch };
4045
4111
  this.isCustomFilterActive();
4046
4112
  await this.applyPlayerFilters();
4047
4113
  return this;
@@ -4063,7 +4129,7 @@ var FilterManager = class {
4063
4129
  this.data = this.data ?? {};
4064
4130
  this.filters.nightcore = false;
4065
4131
  this.filters.vaporwave = false;
4066
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, rate };
4132
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, rate };
4067
4133
  this.isCustomFilterActive();
4068
4134
  await this.applyPlayerFilters();
4069
4135
  return this;
@@ -4492,6 +4558,7 @@ var FilterManager = class {
4492
4558
  if (!this.player.node.sessionId) throw new Error("The Lavalink-Node is either not ready or not up to date");
4493
4559
  const now = performance.now();
4494
4560
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
4561
+ this.player.triggerPlayerClientUpdate();
4495
4562
  await this.player.node.updatePlayer({
4496
4563
  guildId: this.player.guildId,
4497
4564
  playerOptions: {
@@ -4648,7 +4715,7 @@ var Queue = class {
4648
4715
  * @param queueOptions
4649
4716
  */
4650
4717
  constructor(guildId, data = {}, QueueSaver2, queueOptions) {
4651
- this.queueChanges = queueOptions.queueChangesWatcher || null;
4718
+ this.queueChanges = queueOptions?.queueChangesWatcher || null;
4652
4719
  this.guildId = guildId;
4653
4720
  this.QueueSaver = QueueSaver2;
4654
4721
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
@@ -4699,7 +4766,7 @@ var Queue = class {
4699
4766
  ))
4700
4767
  this.previous.splice(
4701
4768
  0,
4702
- override ? this.tracks.length : 0,
4769
+ override ? this.previous.length : 0,
4703
4770
  ...data.previous.filter(
4704
4771
  (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4705
4772
  )
@@ -4714,8 +4781,8 @@ var Queue = class {
4714
4781
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
4715
4782
  */
4716
4783
  toJSON: () => {
4717
- if (this.previous.length > this.options.maxPreviousTracks)
4718
- this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
4784
+ if (this.previous?.length > this.options?.maxPreviousTracks)
4785
+ this.previous?.splice(this.options?.maxPreviousTracks, this.previous.length);
4719
4786
  return {
4720
4787
  current: this.current ? { ...this.current } : null,
4721
4788
  previous: this.previous ? [...this.previous] : [],
@@ -5235,7 +5302,8 @@ var Player = class {
5235
5302
  voice = {
5236
5303
  endpoint: null,
5237
5304
  sessionId: null,
5238
- token: null
5305
+ token: null,
5306
+ channelId: void 0
5239
5307
  };
5240
5308
  voiceState = {
5241
5309
  selfDeaf: false,
@@ -5531,6 +5599,17 @@ var Player = class {
5531
5599
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5532
5600
  return this;
5533
5601
  }
5602
+ /**
5603
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5604
+ */
5605
+ oldJSON = this.toJSON();
5606
+ /**
5607
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5608
+ */
5609
+ triggerPlayerClientUpdate() {
5610
+ this.LavalinkManager.emit("playerClientUpdate", this.oldJSON, this);
5611
+ this.oldJSON = this.toJSON();
5612
+ }
5534
5613
  /**
5535
5614
  * Set the Volume for the Player
5536
5615
  * @param volume The Volume in percent
@@ -5551,6 +5630,7 @@ var Player = class {
5551
5630
  0
5552
5631
  )
5553
5632
  );
5633
+ this.triggerPlayerClientUpdate();
5554
5634
  const now = performance.now();
5555
5635
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
5556
5636
  this._emitDebugEvent("PlayerVolumeAsFilter" /* PlayerVolumeAsFilter */, {
@@ -5625,6 +5705,7 @@ var Player = class {
5625
5705
  this.paused = true;
5626
5706
  this.lastPositionChange = null;
5627
5707
  const now = performance.now();
5708
+ this.triggerPlayerClientUpdate();
5628
5709
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
5629
5710
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5630
5711
  this.LavalinkManager.emit("playerPaused", this, this.queue.current);
@@ -5637,6 +5718,7 @@ var Player = class {
5637
5718
  if (!this.paused) throw new Error("Player isn't paused - not able to resume.");
5638
5719
  this.paused = false;
5639
5720
  const now = performance.now();
5721
+ this.triggerPlayerClientUpdate();
5640
5722
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
5641
5723
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5642
5724
  this.LavalinkManager.emit("playerResumed", this, this.queue.current);
@@ -5657,6 +5739,7 @@ var Player = class {
5657
5739
  this.lastPositionChange = Date.now();
5658
5740
  this.lastPosition = position;
5659
5741
  const now = performance.now();
5742
+ this.triggerPlayerClientUpdate();
5660
5743
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { position } });
5661
5744
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5662
5745
  return this;
@@ -5669,6 +5752,7 @@ var Player = class {
5669
5752
  if (!["off", "track", "queue"].includes(repeatMode))
5670
5753
  throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
5671
5754
  this.repeatMode = repeatMode;
5755
+ this.triggerPlayerClientUpdate();
5672
5756
  return this;
5673
5757
  }
5674
5758
  /**
@@ -5923,7 +6007,7 @@ var Player = class {
5923
6007
  functionLayer: "Player > changeNode()"
5924
6008
  });
5925
6009
  });
5926
- } else {
6010
+ } else if (this.LavalinkManager.options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement !== false) {
5927
6011
  await this.setSponsorBlock().catch((error) => {
5928
6012
  this._emitDebugEvent("PlayerChangeNode" /* PlayerChangeNode */, {
5929
6013
  state: "error",
@@ -5947,7 +6031,8 @@ var Player = class {
5947
6031
  voice: {
5948
6032
  token: this.voice.token,
5949
6033
  endpoint: this.voice.endpoint,
5950
- sessionId: this.voice.sessionId
6034
+ sessionId: this.voice.sessionId,
6035
+ channelId: this.voice.channelId
5951
6036
  }
5952
6037
  }
5953
6038
  });
@@ -6019,13 +6104,13 @@ var Player = class {
6019
6104
  nodeId: this.node?.id,
6020
6105
  nodeSessionId: this.node?.sessionId,
6021
6106
  ping: this.ping,
6022
- queue: this.queue.utils.toJSON()
6107
+ queue: this.queue?.utils?.toJSON?.()
6023
6108
  };
6024
6109
  }
6025
6110
  };
6026
6111
 
6027
6112
  // src/structures/LavalinkManager.ts
6028
- var LavalinkManager = class extends EventEmitter2 {
6113
+ var LavalinkManager = class extends import_node_events2.EventEmitter {
6029
6114
  /**
6030
6115
  * Emit an event
6031
6116
  * @param event The event to emit
@@ -6119,7 +6204,8 @@ var LavalinkManager = class extends EventEmitter2 {
6119
6204
  maxErrorsPerTime: {
6120
6205
  threshold: options?.playerOptions?.maxErrorsPerTime?.threshold ?? 35e3,
6121
6206
  maxAmount: options?.playerOptions?.maxErrorsPerTime?.maxAmount ?? 3
6122
- }
6207
+ },
6208
+ enforceSponsorBlockRequestForEventEnablement: options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement ?? true
6123
6209
  },
6124
6210
  linksWhitelist: options?.linksWhitelist ?? [],
6125
6211
  linksBlacklist: options?.linksBlacklist ?? [],
@@ -6512,17 +6598,43 @@ var LavalinkManager = class extends EventEmitter2 {
6512
6598
  if ("token" in update) {
6513
6599
  if (!player.node?.sessionId) throw new Error("Lavalink Node is either not ready or not up to date");
6514
6600
  const sessionId2Use = player.voice?.sessionId || ("sessionId" in update ? update.sessionId : void 0);
6601
+ const channelId2Use = player.voice?.channelId || ("channel_id" in update ? update.channel_id : void 0);
6515
6602
  if (!sessionId2Use) {
6516
6603
  this.emit("debug", "NoAudioDebug" /* NoAudioDebug */, {
6517
6604
  state: "error",
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)}`,
6605
+ message: `Can't send updatePlayer for voice token session - Missing sessionId :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, channelId: channelId2Use }, update, playerVoice: player.voice }, 2)}`,
6519
6606
  functionLayer: "LavalinkManager > sendRawData()"
6520
6607
  });
6521
6608
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6522
6609
  console.debug(
6523
6610
  "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId",
6524
6611
  {
6525
- voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use },
6612
+ voice: {
6613
+ token: update.token,
6614
+ endpoint: update.endpoint,
6615
+ sessionId: sessionId2Use,
6616
+ channelId: channelId2Use
6617
+ },
6618
+ update,
6619
+ playerVoice: player.voice
6620
+ }
6621
+ );
6622
+ } else if (!channelId2Use) {
6623
+ this.emit("debug", "NoAudioDebug" /* NoAudioDebug */, {
6624
+ state: "error",
6625
+ message: `Can't send updatePlayer for voice token session - Missing channelId :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, channelId: channelId2Use }, update, playerVoice: player.voice }, 2)}`,
6626
+ functionLayer: "LavalinkManager > sendRawData()"
6627
+ });
6628
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6629
+ console.debug(
6630
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing channelId",
6631
+ {
6632
+ voice: {
6633
+ token: update.token,
6634
+ endpoint: update.endpoint,
6635
+ sessionId: sessionId2Use,
6636
+ channelId: channelId2Use
6637
+ },
6526
6638
  update,
6527
6639
  playerVoice: player.voice
6528
6640
  }
@@ -6534,20 +6646,26 @@ var LavalinkManager = class extends EventEmitter2 {
6534
6646
  voice: {
6535
6647
  token: update.token,
6536
6648
  endpoint: update.endpoint,
6537
- sessionId: sessionId2Use
6649
+ sessionId: sessionId2Use,
6650
+ channelId: channelId2Use
6538
6651
  }
6539
6652
  }
6540
6653
  });
6541
6654
  this._emitDebugEvent("NoAudioDebug" /* NoAudioDebug */, {
6542
6655
  state: "log",
6543
- message: `Sent updatePlayer for voice token session :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use }, update, playerVoice: player.voice }, 2)}`,
6656
+ message: `Sent updatePlayer for voice token session :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, channelId: channelId2Use }, update, playerVoice: player.voice }, 2)}`,
6544
6657
  functionLayer: "LavalinkManager > sendRawData()"
6545
6658
  });
6546
6659
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6547
6660
  console.debug(
6548
6661
  "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session",
6549
6662
  {
6550
- voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use },
6663
+ voice: {
6664
+ token: update.token,
6665
+ endpoint: update.endpoint,
6666
+ sessionId: sessionId2Use,
6667
+ channelId: channelId2Use
6668
+ },
6551
6669
  playerVoice: player.voice,
6552
6670
  update
6553
6671
  }
@@ -6582,6 +6700,7 @@ var LavalinkManager = class extends EventEmitter2 {
6582
6700
  if (player.voiceChannelId !== update.channel_id)
6583
6701
  this.emit("playerMove", player, player.voiceChannelId, update.channel_id);
6584
6702
  player.voice.sessionId = update.session_id || player.voice.sessionId;
6703
+ player.voice.channelId = update.channel_id;
6585
6704
  if (!player.voice.sessionId) {
6586
6705
  this._emitDebugEvent("NoAudioDebug" /* NoAudioDebug */, {
6587
6706
  state: "warn",
@@ -6657,7 +6776,8 @@ var LavalinkManager = class extends EventEmitter2 {
6657
6776
  }
6658
6777
  }
6659
6778
  };
6660
- export {
6779
+ // Annotate the CommonJS export names for ESM import in node:
6780
+ 0 && (module.exports = {
6661
6781
  DebugEvents,
6662
6782
  DefaultQueueStore,
6663
6783
  DefaultSources,
@@ -6688,4 +6808,4 @@ export {
6688
6808
  queueTrackEnd,
6689
6809
  safeStringify,
6690
6810
  validSponsorBlocks
6691
- };
6811
+ });
@@ -1,5 +1,5 @@
1
- import { EventEmitter } from 'events';
2
- import { ReadableStream } from 'stream/web';
1
+ import { EventEmitter } from 'node:events';
2
+ import { ReadableStream } from 'node:stream/web';
3
3
 
4
4
  /**
5
5
  * Debug events for more detailed logging
@@ -803,6 +803,8 @@ interface LavalinkPlayerVoice {
803
803
  endpoint: string;
804
804
  /** The Voice SessionId */
805
805
  sessionId: string;
806
+ /** The Voice Channel Id */
807
+ channelId?: string;
806
808
  /** Whether or not the player is connected */
807
809
  connected?: boolean;
808
810
  /** The Ping to the voice server */
@@ -2699,6 +2701,14 @@ declare class Player {
2699
2701
  * @param options
2700
2702
  */
2701
2703
  play(options?: Partial<PlayOptions>): any;
2704
+ /**
2705
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2706
+ */
2707
+ oldJSON: PlayerJson;
2708
+ /**
2709
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2710
+ */
2711
+ triggerPlayerClientUpdate(): void;
2702
2712
  /**
2703
2713
  * Set the Volume for the Player
2704
2714
  * @param volume The Volume in percent
@@ -3793,6 +3803,20 @@ interface LavalinkManagerEvents<CustomPlayerT extends Player = Player> {
3793
3803
  * @event Manager#playerUpdate
3794
3804
  */
3795
3805
  playerUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3806
+ /**
3807
+ * Always emits when the player (on client side) got updated via a function-call.
3808
+ * This is useful for example, if you want to save the player data on every update, or similar.
3809
+ * @event Manager#playerClientUpdate
3810
+ *
3811
+ * Emits only when you call one of those functions:
3812
+ * player.pause()
3813
+ * player.resume()
3814
+ * player.seek()
3815
+ * player.setRepeatMode()
3816
+ * player.setVolume()
3817
+ * and on every call of the filterManager.
3818
+ */
3819
+ playerClientUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3796
3820
  /**
3797
3821
  * Emitted when the player's selfMuted or serverMuted state changed (true -> false | false -> true)
3798
3822
  * @event Manager#playerMuteChange
@@ -3944,6 +3968,14 @@ interface ManagerPlayerOptions<CustomPlayerT extends Player = Player> {
3944
3968
  destroyAfterMs?: number;
3945
3969
  };
3946
3970
  useUnresolvedData?: boolean;
3971
+ /**
3972
+ * If true (default), when changing nodes, `setSponsorBlock()` with default categories is called
3973
+ * even if the user never explicitly set categories. This is needed so the SponsorBlock plugin
3974
+ * registers its event listeners (ChapterStarted/ChapterLoaded) on the new node.
3975
+ * Set to false to disable this behavior if you don't use SponsorBlock events.
3976
+ * @default true
3977
+ */
3978
+ enforceSponsorBlockRequestForEventEnablement?: boolean;
3947
3979
  }
3948
3980
  type DeepRequired<T> = {
3949
3981
  [K in keyof T]-?: NonNullable<T[K]> extends object ? DeepRequired<NonNullable<T[K]>> : NonNullable<T[K]>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { EventEmitter } from 'events';
2
- import { ReadableStream } from 'stream/web';
1
+ import { EventEmitter } from 'node:events';
2
+ import { ReadableStream } from 'node:stream/web';
3
3
 
4
4
  /**
5
5
  * Debug events for more detailed logging
@@ -803,6 +803,8 @@ interface LavalinkPlayerVoice {
803
803
  endpoint: string;
804
804
  /** The Voice SessionId */
805
805
  sessionId: string;
806
+ /** The Voice Channel Id */
807
+ channelId?: string;
806
808
  /** Whether or not the player is connected */
807
809
  connected?: boolean;
808
810
  /** The Ping to the voice server */
@@ -2699,6 +2701,14 @@ declare class Player {
2699
2701
  * @param options
2700
2702
  */
2701
2703
  play(options?: Partial<PlayOptions>): any;
2704
+ /**
2705
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2706
+ */
2707
+ oldJSON: PlayerJson;
2708
+ /**
2709
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2710
+ */
2711
+ triggerPlayerClientUpdate(): void;
2702
2712
  /**
2703
2713
  * Set the Volume for the Player
2704
2714
  * @param volume The Volume in percent
@@ -3793,6 +3803,20 @@ interface LavalinkManagerEvents<CustomPlayerT extends Player = Player> {
3793
3803
  * @event Manager#playerUpdate
3794
3804
  */
3795
3805
  playerUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3806
+ /**
3807
+ * Always emits when the player (on client side) got updated via a function-call.
3808
+ * This is useful for example, if you want to save the player data on every update, or similar.
3809
+ * @event Manager#playerClientUpdate
3810
+ *
3811
+ * Emits only when you call one of those functions:
3812
+ * player.pause()
3813
+ * player.resume()
3814
+ * player.seek()
3815
+ * player.setRepeatMode()
3816
+ * player.setVolume()
3817
+ * and on every call of the filterManager.
3818
+ */
3819
+ playerClientUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3796
3820
  /**
3797
3821
  * Emitted when the player's selfMuted or serverMuted state changed (true -> false | false -> true)
3798
3822
  * @event Manager#playerMuteChange
@@ -3944,6 +3968,14 @@ interface ManagerPlayerOptions<CustomPlayerT extends Player = Player> {
3944
3968
  destroyAfterMs?: number;
3945
3969
  };
3946
3970
  useUnresolvedData?: boolean;
3971
+ /**
3972
+ * If true (default), when changing nodes, `setSponsorBlock()` with default categories is called
3973
+ * even if the user never explicitly set categories. This is needed so the SponsorBlock plugin
3974
+ * registers its event listeners (ChapterStarted/ChapterLoaded) on the new node.
3975
+ * Set to false to disable this behavior if you don't use SponsorBlock events.
3976
+ * @default true
3977
+ */
3978
+ enforceSponsorBlockRequestForEventEnablement?: boolean;
3947
3979
  }
3948
3980
  type DeepRequired<T> = {
3949
3981
  [K in keyof T]-?: NonNullable<T[K]> extends object ? DeepRequired<NonNullable<T[K]>> : NonNullable<T[K]>;
package/dist/index.js CHANGED
@@ -1,69 +1,5 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // src/index.ts
30
- var index_exports = {};
31
- __export(index_exports, {
32
- DebugEvents: () => DebugEvents,
33
- DefaultQueueStore: () => DefaultQueueStore,
34
- DefaultSources: () => DefaultSources,
35
- DestroyReasons: () => DestroyReasons,
36
- DisconnectReasons: () => DisconnectReasons,
37
- EQList: () => EQList,
38
- FilterManager: () => FilterManager,
39
- LavalinkManager: () => LavalinkManager,
40
- LavalinkNode: () => LavalinkNode,
41
- LavalinkPlugins: () => LavalinkPlugins,
42
- ManagerUtils: () => ManagerUtils,
43
- MiniMap: () => MiniMap,
44
- NodeLinkExclusiveEvents: () => NodeLinkExclusiveEvents,
45
- NodeLinkNode: () => NodeLinkNode,
46
- NodeManager: () => NodeManager,
47
- NodeSymbol: () => NodeSymbol,
48
- Player: () => Player,
49
- Queue: () => Queue,
50
- QueueSaver: () => QueueSaver,
51
- QueueSymbol: () => QueueSymbol,
52
- RecommendationsStrings: () => RecommendationsStrings,
53
- ReconnectionState: () => ReconnectionState,
54
- SourceLinksRegexes: () => SourceLinksRegexes,
55
- TrackSymbol: () => TrackSymbol,
56
- UnresolvedTrackSymbol: () => UnresolvedTrackSymbol,
57
- audioOutputsData: () => audioOutputsData,
58
- parseLavalinkConnUrl: () => parseLavalinkConnUrl,
59
- queueTrackEnd: () => queueTrackEnd,
60
- safeStringify: () => safeStringify,
61
- validSponsorBlocks: () => validSponsorBlocks
62
- });
63
- module.exports = __toCommonJS(index_exports);
64
-
65
1
  // src/structures/LavalinkManager.ts
66
- var import_events2 = require("events");
2
+ import { EventEmitter as EventEmitter2 } from "events";
67
3
 
68
4
  // src/structures/Constants.ts
69
5
  var DebugEvents = /* @__PURE__ */ ((DebugEvents2) => {
@@ -404,11 +340,11 @@ var NodeLinkExclusiveEvents = [
404
340
  ];
405
341
 
406
342
  // src/structures/NodeManager.ts
407
- var import_events = require("events");
343
+ import { EventEmitter } from "events";
408
344
 
409
345
  // src/structures/Node.ts
410
- var import_path = require("path");
411
- var import_ws = __toESM(require("ws"));
346
+ import { isAbsolute } from "path";
347
+ import WebSocket from "ws";
412
348
 
413
349
  // src/structures/Types/Node.ts
414
350
  var ReconnectionState = /* @__PURE__ */ ((ReconnectionState2) => {
@@ -420,8 +356,8 @@ var ReconnectionState = /* @__PURE__ */ ((ReconnectionState2) => {
420
356
  })(ReconnectionState || {});
421
357
 
422
358
  // src/structures/Utils.ts
423
- var import_node_url = require("url");
424
- var import_types = require("util/types");
359
+ import { URL as URL2 } from "url";
360
+ import { isRegExp } from "util/types";
425
361
 
426
362
  // src/structures/LavalinkManagerStatics.ts
427
363
  var DefaultSources = {
@@ -591,7 +527,7 @@ var escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
591
527
  function parseLavalinkConnUrl(connectionUrl) {
592
528
  if (!connectionUrl.startsWith("lavalink://"))
593
529
  throw new Error(`ConnectionUrl (${connectionUrl}) must start with 'lavalink://'`);
594
- const parsed = new import_node_url.URL(connectionUrl);
530
+ const parsed = new URL2(connectionUrl);
595
531
  return {
596
532
  authorization: parsed.password,
597
533
  id: parsed.username,
@@ -856,7 +792,7 @@ var ManagerUtils = class {
856
792
  });
857
793
  }
858
794
  if (this.LavalinkManager.options?.linksBlacklist.some(
859
- (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || (0, import_types.isRegExp)(v) && v.test(queryString)
795
+ (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString)
860
796
  )) {
861
797
  throw new Error(`Query string contains a link / word which is blacklisted.`);
862
798
  }
@@ -873,7 +809,7 @@ var ManagerUtils = class {
873
809
  });
874
810
  }
875
811
  if (!this.LavalinkManager.options?.linksWhitelist.some(
876
- (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || (0, import_types.isRegExp)(v) && v.test(queryString)
812
+ (v) => typeof v === "string" && queryString.toLowerCase().includes(v.toLowerCase()) || isRegExp(v) && v.test(queryString)
877
813
  )) {
878
814
  throw new Error(`Query string contains a link / word which isn't whitelisted.`);
879
815
  }
@@ -1349,7 +1285,7 @@ var LavalinkNode = class _LavalinkNode {
1349
1285
  * ```
1350
1286
  */
1351
1287
  get connected() {
1352
- return this.socket && this.socket.readyState === import_ws.default.OPEN;
1288
+ return this.socket && this.socket.readyState === WebSocket.OPEN;
1353
1289
  }
1354
1290
  /**
1355
1291
  * Returns the current ConnectionStatus
@@ -1669,7 +1605,7 @@ var LavalinkNode = class _LavalinkNode {
1669
1605
  headers["Session-Id"] = this.options.sessionId || sessionId;
1670
1606
  this.sessionId = this.options.sessionId || sessionId;
1671
1607
  }
1672
- this.socket = new import_ws.default(
1608
+ this.socket = new WebSocket(
1673
1609
  `ws${this.options.secure ? "s" : ""}://${this.options.host}:${this.options.port}/v4/websocket`,
1674
1610
  { headers }
1675
1611
  );
@@ -2581,12 +2517,13 @@ var LavalinkNode = class _LavalinkNode {
2581
2517
  if (!error) return;
2582
2518
  this.NodeManager.emit("error", this, error);
2583
2519
  this.reconnectionState = "IDLE" /* IDLE */;
2584
- this.reconnect();
2585
2520
  if (this.options.closeOnError) {
2586
2521
  if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
2587
2522
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
2588
2523
  this.socket?.close(500, "Node-Error - Force Reconnect");
2524
+ return;
2589
2525
  }
2526
+ this.reconnect();
2590
2527
  }
2591
2528
  /** @private util function for handling message events from websocket */
2592
2529
  async message(d) {
@@ -2622,7 +2559,7 @@ var LavalinkNode = class _LavalinkNode {
2622
2559
  player.connected = payload.state.connected;
2623
2560
  player.ping.ws = payload.state.ping >= 0 ? payload.state.ping : player.ping.ws <= 0 && player.connected ? null : player.ping.ws || 0;
2624
2561
  if (!player.createdTimeStamp && payload.state.time) player.createdTimeStamp = payload.state.time;
2625
- if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 6e5) || player.queue.current?.info?.uri && (0, import_path.isAbsolute)(player.queue.current?.info?.uri))) {
2562
+ if (player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 6e5) || player.queue.current?.info?.uri && isAbsolute(player.queue.current?.info?.uri))) {
2626
2563
  player.filterManager.filterUpdatedState = false;
2627
2564
  this._emitDebugEvent("PlayerUpdateFilterFixApply" /* PlayerUpdateFilterFixApply */, {
2628
2565
  state: "log",
@@ -2810,7 +2747,7 @@ var LavalinkNode = class _LavalinkNode {
2810
2747
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2811
2748
  );
2812
2749
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2813
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2750
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2814
2751
  this._emitDebugEvent("TrackStuckMaxTracksErroredPerTime" /* TrackStuckMaxTracksErroredPerTime */, {
2815
2752
  state: "log",
2816
2753
  message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -2848,7 +2785,7 @@ var LavalinkNode = class _LavalinkNode {
2848
2785
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2849
2786
  );
2850
2787
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2851
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2788
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2852
2789
  this._emitDebugEvent("TrackErrorMaxTracksErroredPerTime" /* TrackErrorMaxTracksErroredPerTime */, {
2853
2790
  state: "log",
2854
2791
  message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -3427,7 +3364,7 @@ var NodeLinkNode = class extends LavalinkNode {
3427
3364
  LavalinkNode._NodeLinkClass = NodeLinkNode;
3428
3365
 
3429
3366
  // src/structures/NodeManager.ts
3430
- var NodeManager = class extends import_events.EventEmitter {
3367
+ var NodeManager = class extends EventEmitter {
3431
3368
  /**
3432
3369
  * Emit an event
3433
3370
  * @param event The event to emit
@@ -3908,6 +3845,7 @@ var FilterManager = class {
3908
3845
  }
3909
3846
  const now = performance.now();
3910
3847
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
3848
+ this.player.triggerPlayerClientUpdate();
3911
3849
  await this.player.node.updatePlayer({
3912
3850
  guildId: this.player.guildId,
3913
3851
  playerOptions: {
@@ -4002,7 +3940,7 @@ var FilterManager = class {
4002
3940
  this.filters.tremolo = false;
4003
3941
  this.filters.vibrato = false;
4004
3942
  this.filters.karaoke = false;
4005
- this.filters.karaoke = false;
3943
+ this.filters.vaporwave = false;
4006
3944
  this.filters.volume = false;
4007
3945
  this.filters.nodeLinkEcho = false;
4008
3946
  this.filters.nodeLinkChorus = false;
@@ -4083,7 +4021,7 @@ var FilterManager = class {
4083
4021
  this.data = this.data ?? {};
4084
4022
  this.filters.nightcore = false;
4085
4023
  this.filters.vaporwave = false;
4086
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, speed };
4024
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, speed };
4087
4025
  this.isCustomFilterActive();
4088
4026
  await this.applyPlayerFilters();
4089
4027
  return this;
@@ -4105,7 +4043,7 @@ var FilterManager = class {
4105
4043
  this.data = this.data ?? {};
4106
4044
  this.filters.nightcore = false;
4107
4045
  this.filters.vaporwave = false;
4108
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, pitch };
4046
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, pitch };
4109
4047
  this.isCustomFilterActive();
4110
4048
  await this.applyPlayerFilters();
4111
4049
  return this;
@@ -4127,7 +4065,7 @@ var FilterManager = class {
4127
4065
  this.data = this.data ?? {};
4128
4066
  this.filters.nightcore = false;
4129
4067
  this.filters.vaporwave = false;
4130
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, rate };
4068
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, rate };
4131
4069
  this.isCustomFilterActive();
4132
4070
  await this.applyPlayerFilters();
4133
4071
  return this;
@@ -4556,6 +4494,7 @@ var FilterManager = class {
4556
4494
  if (!this.player.node.sessionId) throw new Error("The Lavalink-Node is either not ready or not up to date");
4557
4495
  const now = performance.now();
4558
4496
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
4497
+ this.player.triggerPlayerClientUpdate();
4559
4498
  await this.player.node.updatePlayer({
4560
4499
  guildId: this.player.guildId,
4561
4500
  playerOptions: {
@@ -4712,7 +4651,7 @@ var Queue = class {
4712
4651
  * @param queueOptions
4713
4652
  */
4714
4653
  constructor(guildId, data = {}, QueueSaver2, queueOptions) {
4715
- this.queueChanges = queueOptions.queueChangesWatcher || null;
4654
+ this.queueChanges = queueOptions?.queueChangesWatcher || null;
4716
4655
  this.guildId = guildId;
4717
4656
  this.QueueSaver = QueueSaver2;
4718
4657
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
@@ -4763,7 +4702,7 @@ var Queue = class {
4763
4702
  ))
4764
4703
  this.previous.splice(
4765
4704
  0,
4766
- override ? this.tracks.length : 0,
4705
+ override ? this.previous.length : 0,
4767
4706
  ...data.previous.filter(
4768
4707
  (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4769
4708
  )
@@ -4778,8 +4717,8 @@ var Queue = class {
4778
4717
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
4779
4718
  */
4780
4719
  toJSON: () => {
4781
- if (this.previous.length > this.options.maxPreviousTracks)
4782
- this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
4720
+ if (this.previous?.length > this.options?.maxPreviousTracks)
4721
+ this.previous?.splice(this.options?.maxPreviousTracks, this.previous.length);
4783
4722
  return {
4784
4723
  current: this.current ? { ...this.current } : null,
4785
4724
  previous: this.previous ? [...this.previous] : [],
@@ -5299,7 +5238,8 @@ var Player = class {
5299
5238
  voice = {
5300
5239
  endpoint: null,
5301
5240
  sessionId: null,
5302
- token: null
5241
+ token: null,
5242
+ channelId: void 0
5303
5243
  };
5304
5244
  voiceState = {
5305
5245
  selfDeaf: false,
@@ -5595,6 +5535,17 @@ var Player = class {
5595
5535
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5596
5536
  return this;
5597
5537
  }
5538
+ /**
5539
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5540
+ */
5541
+ oldJSON = this.toJSON();
5542
+ /**
5543
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5544
+ */
5545
+ triggerPlayerClientUpdate() {
5546
+ this.LavalinkManager.emit("playerClientUpdate", this.oldJSON, this);
5547
+ this.oldJSON = this.toJSON();
5548
+ }
5598
5549
  /**
5599
5550
  * Set the Volume for the Player
5600
5551
  * @param volume The Volume in percent
@@ -5615,6 +5566,7 @@ var Player = class {
5615
5566
  0
5616
5567
  )
5617
5568
  );
5569
+ this.triggerPlayerClientUpdate();
5618
5570
  const now = performance.now();
5619
5571
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
5620
5572
  this._emitDebugEvent("PlayerVolumeAsFilter" /* PlayerVolumeAsFilter */, {
@@ -5689,6 +5641,7 @@ var Player = class {
5689
5641
  this.paused = true;
5690
5642
  this.lastPositionChange = null;
5691
5643
  const now = performance.now();
5644
+ this.triggerPlayerClientUpdate();
5692
5645
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
5693
5646
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5694
5647
  this.LavalinkManager.emit("playerPaused", this, this.queue.current);
@@ -5701,6 +5654,7 @@ var Player = class {
5701
5654
  if (!this.paused) throw new Error("Player isn't paused - not able to resume.");
5702
5655
  this.paused = false;
5703
5656
  const now = performance.now();
5657
+ this.triggerPlayerClientUpdate();
5704
5658
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
5705
5659
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5706
5660
  this.LavalinkManager.emit("playerResumed", this, this.queue.current);
@@ -5721,6 +5675,7 @@ var Player = class {
5721
5675
  this.lastPositionChange = Date.now();
5722
5676
  this.lastPosition = position;
5723
5677
  const now = performance.now();
5678
+ this.triggerPlayerClientUpdate();
5724
5679
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { position } });
5725
5680
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5726
5681
  return this;
@@ -5733,6 +5688,7 @@ var Player = class {
5733
5688
  if (!["off", "track", "queue"].includes(repeatMode))
5734
5689
  throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
5735
5690
  this.repeatMode = repeatMode;
5691
+ this.triggerPlayerClientUpdate();
5736
5692
  return this;
5737
5693
  }
5738
5694
  /**
@@ -5987,7 +5943,7 @@ var Player = class {
5987
5943
  functionLayer: "Player > changeNode()"
5988
5944
  });
5989
5945
  });
5990
- } else {
5946
+ } else if (this.LavalinkManager.options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement !== false) {
5991
5947
  await this.setSponsorBlock().catch((error) => {
5992
5948
  this._emitDebugEvent("PlayerChangeNode" /* PlayerChangeNode */, {
5993
5949
  state: "error",
@@ -6011,7 +5967,8 @@ var Player = class {
6011
5967
  voice: {
6012
5968
  token: this.voice.token,
6013
5969
  endpoint: this.voice.endpoint,
6014
- sessionId: this.voice.sessionId
5970
+ sessionId: this.voice.sessionId,
5971
+ channelId: this.voice.channelId
6015
5972
  }
6016
5973
  }
6017
5974
  });
@@ -6083,13 +6040,13 @@ var Player = class {
6083
6040
  nodeId: this.node?.id,
6084
6041
  nodeSessionId: this.node?.sessionId,
6085
6042
  ping: this.ping,
6086
- queue: this.queue.utils.toJSON()
6043
+ queue: this.queue?.utils?.toJSON?.()
6087
6044
  };
6088
6045
  }
6089
6046
  };
6090
6047
 
6091
6048
  // src/structures/LavalinkManager.ts
6092
- var LavalinkManager = class extends import_events2.EventEmitter {
6049
+ var LavalinkManager = class extends EventEmitter2 {
6093
6050
  /**
6094
6051
  * Emit an event
6095
6052
  * @param event The event to emit
@@ -6183,7 +6140,8 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6183
6140
  maxErrorsPerTime: {
6184
6141
  threshold: options?.playerOptions?.maxErrorsPerTime?.threshold ?? 35e3,
6185
6142
  maxAmount: options?.playerOptions?.maxErrorsPerTime?.maxAmount ?? 3
6186
- }
6143
+ },
6144
+ enforceSponsorBlockRequestForEventEnablement: options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement ?? true
6187
6145
  },
6188
6146
  linksWhitelist: options?.linksWhitelist ?? [],
6189
6147
  linksBlacklist: options?.linksBlacklist ?? [],
@@ -6576,17 +6534,43 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6576
6534
  if ("token" in update) {
6577
6535
  if (!player.node?.sessionId) throw new Error("Lavalink Node is either not ready or not up to date");
6578
6536
  const sessionId2Use = player.voice?.sessionId || ("sessionId" in update ? update.sessionId : void 0);
6537
+ const channelId2Use = player.voice?.channelId || ("channel_id" in update ? update.channel_id : void 0);
6579
6538
  if (!sessionId2Use) {
6580
6539
  this.emit("debug", "NoAudioDebug" /* NoAudioDebug */, {
6581
6540
  state: "error",
6582
- 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)}`,
6541
+ message: `Can't send updatePlayer for voice token session - Missing sessionId :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, channelId: channelId2Use }, update, playerVoice: player.voice }, 2)}`,
6583
6542
  functionLayer: "LavalinkManager > sendRawData()"
6584
6543
  });
6585
6544
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6586
6545
  console.debug(
6587
6546
  "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId",
6588
6547
  {
6589
- voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use },
6548
+ voice: {
6549
+ token: update.token,
6550
+ endpoint: update.endpoint,
6551
+ sessionId: sessionId2Use,
6552
+ channelId: channelId2Use
6553
+ },
6554
+ update,
6555
+ playerVoice: player.voice
6556
+ }
6557
+ );
6558
+ } else if (!channelId2Use) {
6559
+ this.emit("debug", "NoAudioDebug" /* NoAudioDebug */, {
6560
+ state: "error",
6561
+ message: `Can't send updatePlayer for voice token session - Missing channelId :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, channelId: channelId2Use }, update, playerVoice: player.voice }, 2)}`,
6562
+ functionLayer: "LavalinkManager > sendRawData()"
6563
+ });
6564
+ if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6565
+ console.debug(
6566
+ "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing channelId",
6567
+ {
6568
+ voice: {
6569
+ token: update.token,
6570
+ endpoint: update.endpoint,
6571
+ sessionId: sessionId2Use,
6572
+ channelId: channelId2Use
6573
+ },
6590
6574
  update,
6591
6575
  playerVoice: player.voice
6592
6576
  }
@@ -6598,20 +6582,26 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6598
6582
  voice: {
6599
6583
  token: update.token,
6600
6584
  endpoint: update.endpoint,
6601
- sessionId: sessionId2Use
6585
+ sessionId: sessionId2Use,
6586
+ channelId: channelId2Use
6602
6587
  }
6603
6588
  }
6604
6589
  });
6605
6590
  this._emitDebugEvent("NoAudioDebug" /* NoAudioDebug */, {
6606
6591
  state: "log",
6607
- message: `Sent updatePlayer for voice token session :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use }, update, playerVoice: player.voice }, 2)}`,
6592
+ message: `Sent updatePlayer for voice token session :: ${safeStringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, channelId: channelId2Use }, update, playerVoice: player.voice }, 2)}`,
6608
6593
  functionLayer: "LavalinkManager > sendRawData()"
6609
6594
  });
6610
6595
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
6611
6596
  console.debug(
6612
6597
  "Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session",
6613
6598
  {
6614
- voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use },
6599
+ voice: {
6600
+ token: update.token,
6601
+ endpoint: update.endpoint,
6602
+ sessionId: sessionId2Use,
6603
+ channelId: channelId2Use
6604
+ },
6615
6605
  playerVoice: player.voice,
6616
6606
  update
6617
6607
  }
@@ -6646,6 +6636,7 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6646
6636
  if (player.voiceChannelId !== update.channel_id)
6647
6637
  this.emit("playerMove", player, player.voiceChannelId, update.channel_id);
6648
6638
  player.voice.sessionId = update.session_id || player.voice.sessionId;
6639
+ player.voice.channelId = update.channel_id;
6649
6640
  if (!player.voice.sessionId) {
6650
6641
  this._emitDebugEvent("NoAudioDebug" /* NoAudioDebug */, {
6651
6642
  state: "warn",
@@ -6721,8 +6712,7 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6721
6712
  }
6722
6713
  }
6723
6714
  };
6724
- // Annotate the CommonJS export names for ESM import in node:
6725
- 0 && (module.exports = {
6715
+ export {
6726
6716
  DebugEvents,
6727
6717
  DefaultQueueStore,
6728
6718
  DefaultSources,
@@ -6753,4 +6743,4 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6753
6743
  queueTrackEnd,
6754
6744
  safeStringify,
6755
6745
  validSponsorBlocks
6756
- });
6746
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavalink-client",
3
- "version": "2.9.1",
3
+ "version": "2.9.3",
4
4
  "description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients. - Supports NodeLink@v3 too.",
5
5
  "keywords": [
6
6
  "advanced",
@@ -32,6 +32,7 @@
32
32
  "files": [
33
33
  "dist"
34
34
  ],
35
+ "type": "module",
35
36
  "main": "./dist/index.js",
36
37
  "module": "./dist/index.mjs",
37
38
  "types": "./dist/index.d.ts",
@@ -57,13 +58,14 @@
57
58
  },
58
59
  "dependencies": {
59
60
  "tslib": "^2.8.1",
60
- "ws": "^8.18.3"
61
+ "ws": "^8.19.0"
61
62
  },
62
63
  "devDependencies": {
63
- "@types/node": "^24.10.1",
64
+ "@types/bun": "latest",
65
+ "@types/node": "^24.10.15",
64
66
  "@types/ws": "^8.18.1",
65
67
  "oxfmt": "^0.28.0",
66
- "oxlint": "^1.43.0",
68
+ "oxlint": "^1.50.0",
67
69
  "tsup": "^8.5.1",
68
70
  "typescript": "^5.9.3"
69
71
  },
@@ -71,6 +73,7 @@
71
73
  "bun": ">=1.1.27",
72
74
  "node": ">=18.0.0"
73
75
  },
76
+ "packageManager": "bun@1.3.9",
74
77
  "pnpm": {
75
78
  "onlyBuiltDependencies": [
76
79
  "esbuild"