aqualink 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.
@@ -4,7 +4,7 @@ const Player = require("./Player");
4
4
  const Track = require("./Track");
5
5
  const { version: pkgVersion } = require("../../package.json");
6
6
  const { EventEmitter } = require('tseep');
7
- const fs = require('fs-extra');
7
+ const fs = require('fs/promises');
8
8
 
9
9
  const URL_REGEX = /^https?:\/\//;
10
10
  const DEFAULT_OPTIONS = Object.freeze({
@@ -57,13 +57,21 @@ class Aqua extends EventEmitter {
57
57
  this.send = this.options.send || this.defaultSendFunction.bind(this);
58
58
 
59
59
  this._leastUsedCache = { nodes: [], timestamp: 0 };
60
-
60
+
61
61
  this._nodeStates = new Map();
62
62
  this._failoverQueue = new Map();
63
63
  this._lastFailoverAttempt = new Map();
64
-
64
+
65
+ this._brokenPlayers = new Map();
66
+ this._nodeReconnectHandlers = new Map();
67
+
65
68
  this._boundCleanupPlayer = this.cleanupPlayer.bind(this);
66
69
  this._boundHandlePlayerDestroy = this._handlePlayerDestroy.bind(this);
70
+ this._boundHandleNodeReconnect = this._handleNodeReconnect.bind(this);
71
+ this._boundHandleSocketClosed = this._handleSocketClosed.bind(this);
72
+
73
+ this.on('nodeConnect', (node) => this._handleNodeReconnect(node));
74
+ this.on('nodeDisconnect', (node) => this._handleSocketClosed(node));
67
75
  }
68
76
 
69
77
  defaultSendFunction(packet) {
@@ -100,16 +108,16 @@ class Aqua extends EventEmitter {
100
108
  console.error(`Failed to create node ${node.name || node.host}:`, err);
101
109
  return null;
102
110
  }));
103
-
111
+
104
112
  const results = await Promise.allSettled(nodePromises);
105
113
  const successfulNodes = results.filter(r => r.status === 'fulfilled' && r.value).length;
106
-
114
+
107
115
  if (successfulNodes === 0) {
108
116
  throw new Error("No nodes could be connected");
109
117
  }
110
118
 
111
- await Promise.all(this.plugins.map(plugin =>
112
- Promise.resolve(plugin.load(this)).catch(err =>
119
+ await Promise.all(this.plugins.map(plugin =>
120
+ Promise.resolve(plugin.load(this)).catch(err =>
113
121
  console.error("Plugin load error:", err)
114
122
  )
115
123
  ));
@@ -128,6 +136,7 @@ class Aqua extends EventEmitter {
128
136
  this.destroyNode(nodeId);
129
137
 
130
138
  const node = new Node(this, options, this.options);
139
+ node.players = new Set();
131
140
  this.nodeMap.set(nodeId, node);
132
141
  this._invalidateCache();
133
142
 
@@ -144,6 +153,116 @@ class Aqua extends EventEmitter {
144
153
  }
145
154
  }
146
155
 
156
+ async _handleNodeReconnect(node) {
157
+ if (!this.autoResume) return;
158
+
159
+ const nodeId = node.name || node.host;
160
+ this.emit("debug", "Aqua", `Node ${nodeId} reconnected, attempting to rebuild broken players`);
161
+
162
+ this._nodeStates.set(nodeId, { connected: true, failoverInProgress: false });
163
+
164
+ await this._rebuildBrokenPlayers(node);
165
+ }
166
+
167
+ async _handleSocketClosed(node) {
168
+ if (!this.autoResume) return;
169
+
170
+ const nodeId = node.name || node.host;
171
+ this.emit("debug", "Aqua", `Socket closed for node ${nodeId}, storing broken players`);
172
+
173
+ this._nodeStates.set(nodeId, { connected: false, failoverInProgress: false });
174
+
175
+ await this._storeBrokenPlayersForNode(node);
176
+ }
177
+
178
+ async _storeBrokenPlayersForNode(node) {
179
+ const nodeId = node.name || node.host;
180
+ const affectedPlayers = await this._getPlayersForNode(node);
181
+
182
+
183
+ for (const player of affectedPlayers) {
184
+ try {
185
+ const playerState = this._capturePlayerState(player);
186
+ if (playerState) {
187
+ playerState.originalNodeId = nodeId;
188
+ playerState.brokenAt = Date.now();
189
+ this._brokenPlayers.set(player.guildId, playerState);
190
+
191
+ this.emit("debug", "Aqua", `Stored broken player state for guild ${player.guildId}`);
192
+ }
193
+ } catch (error) {
194
+ this.emit("error", null, new Error(`Failed to store broken player state: ${error.message}`));
195
+ }
196
+ }
197
+ }
198
+
199
+ async _getPlayersForNode(node) {
200
+ const affectedPlayers = [];
201
+ for (const player of this.players.values()) {
202
+ if (player.nodes === node || player.nodes?.name === node.name) {
203
+ affectedPlayers.push(player);
204
+ }
205
+ }
206
+ return affectedPlayers;
207
+ }
208
+
209
+ async _rebuildBrokenPlayers(node) {
210
+ const nodeId = node.name || node.host;
211
+ const rebuiltCount = 0;
212
+
213
+
214
+
215
+ for (const [guildId, brokenState] of this._brokenPlayers.entries()) {
216
+ if (brokenState.originalNodeId !== nodeId) continue;
217
+ try {
218
+ await this._rebuildPlayer(brokenState, node);
219
+ this._brokenPlayers.delete(guildId);
220
+ rebuiltCount++;
221
+
222
+
223
+ this.emit("debug", "Aqua", `Successfully rebuilt player for guild ${guildId}`);
224
+ } catch (error) {
225
+ this.emit("error", null, new Error(`Failed to rebuild player for guild ${guildId}: ${error.message}`));
226
+
227
+ if (Date.now() - brokenState.brokenAt > 300000) {
228
+ this._brokenPlayers.delete(guildId);
229
+ }
230
+ }
231
+ }
232
+
233
+ if (rebuiltCount > 0) {
234
+ this.emit("playersRebuilt", node, rebuiltCount);
235
+ }
236
+ }
237
+
238
+ async _rebuildPlayer(brokenState, targetNode) {
239
+ const { guildId, textChannel, voiceChannel, current, volume = 65, deaf = true } = brokenState;
240
+
241
+ const connectionOptions = { guildId, textChannel, voiceChannel, defaultVolume: volume, deaf };
242
+ const existingPlayer = this.players.get(guildId);
243
+
244
+ if (existingPlayer) {
245
+ await existingPlayer.destroy();
246
+ }
247
+
248
+ setTimeout(async () => {
249
+ const newestPlayer = await this.createConnection(connectionOptions);
250
+ this.players.set(guildId, newestPlayer);
251
+
252
+ if (current) {
253
+ try {
254
+ await newestPlayer.queue.add(current);
255
+ await newestPlayer.play();
256
+ } catch (error) {
257
+ console.error("Error while playing track:", error);
258
+ }
259
+ }
260
+
261
+ this.emit("trackStart", newestPlayer, brokenState.current);
262
+ return newestPlayer;
263
+ }, 2000);
264
+ }
265
+
147
266
  destroyNode(identifier) {
148
267
  const node = this.nodeMap.get(identifier);
149
268
  if (!node) return;
@@ -153,6 +272,11 @@ class Aqua extends EventEmitter {
153
272
  }
154
273
 
155
274
  _cleanupNode(nodeId) {
275
+ const node = this.nodeMap.get(nodeId);
276
+ if (node) {
277
+ node.removeAllListeners();
278
+ }
279
+
156
280
  this.nodeMap.delete(nodeId);
157
281
  this._nodeStates.delete(nodeId);
158
282
  this._failoverQueue.delete(nodeId);
@@ -166,10 +290,10 @@ class Aqua extends EventEmitter {
166
290
 
167
291
  async handleNodeFailover(failedNode) {
168
292
  if (!this.failoverOptions.enabled) return;
169
-
293
+
170
294
  const nodeId = failedNode.name || failedNode.host;
171
295
  const now = Date.now();
172
-
296
+
173
297
  const nodeState = this._nodeStates.get(nodeId);
174
298
  if (nodeState?.failoverInProgress) return;
175
299
 
@@ -182,11 +306,11 @@ class Aqua extends EventEmitter {
182
306
  this._nodeStates.set(nodeId, { connected: false, failoverInProgress: true });
183
307
  this._lastFailoverAttempt.set(nodeId, now);
184
308
  this._failoverQueue.set(nodeId, currentAttempts + 1);
185
-
309
+
186
310
  try {
187
311
  this.emit("nodeFailover", failedNode);
188
-
189
- const affectedPlayers = this._getPlayersForNode(failedNode);
312
+
313
+ const affectedPlayers = Array.from(failedNode.players);
190
314
  if (affectedPlayers.length === 0) {
191
315
  this._nodeStates.set(nodeId, { connected: false, failoverInProgress: false });
192
316
  return;
@@ -200,14 +324,14 @@ class Aqua extends EventEmitter {
200
324
  }
201
325
 
202
326
  const failoverResults = await this._migratePlayersWithRetry(affectedPlayers, availableNodes);
203
-
327
+
204
328
  const successful = failoverResults.filter(r => r.success).length;
205
329
  const failed = failoverResults.length - successful;
206
-
330
+
207
331
  if (successful > 0) {
208
332
  this.emit("nodeFailoverComplete", failedNode, successful, failed);
209
333
  }
210
-
334
+
211
335
  } catch (error) {
212
336
  this.emit("error", null, new Error(`Failover failed for node ${nodeId}: ${error.message}`));
213
337
  } finally {
@@ -215,25 +339,9 @@ class Aqua extends EventEmitter {
215
339
  }
216
340
  }
217
341
 
218
- _getPlayersForNode(node) {
219
- const affectedPlayers = [];
220
- for (const player of this.players.values()) {
221
- if (player.nodes === node || player.nodes?.name === node.name) {
222
- affectedPlayers.push(player);
223
- }
224
- }
225
- return affectedPlayers;
226
- }
227
-
228
- _getAvailableNodesForFailover(failedNode) {
229
- return this.leastUsedNodes.filter(node =>
230
- node !== failedNode && node.name !== failedNode.name
231
- );
232
- }
233
-
234
342
  async _migratePlayersWithRetry(players, availableNodes) {
235
343
  const results = [];
236
-
344
+
237
345
  const concurrency = 3;
238
346
  for (let i = 0; i < players.length; i += concurrency) {
239
347
  const batch = players.slice(i, i + concurrency);
@@ -246,11 +354,11 @@ class Aqua extends EventEmitter {
246
354
  return { player, success: false, error };
247
355
  }
248
356
  });
249
-
357
+
250
358
  const batchResults = await Promise.allSettled(batchPromises);
251
359
  results.push(...batchResults.map(r => r.value || r.reason));
252
360
  }
253
-
361
+
254
362
  return results;
255
363
  }
256
364
 
@@ -261,7 +369,7 @@ class Aqua extends EventEmitter {
261
369
 
262
370
  const guildId = player.guildId;
263
371
  let retryCount = 0;
264
-
372
+
265
373
  while (retryCount < this.failoverOptions.maxRetries) {
266
374
  try {
267
375
  const targetNode = this._selectBestNode(availableNodes, player);
@@ -274,15 +382,14 @@ class Aqua extends EventEmitter {
274
382
  if (!newPlayer) throw new Error("Failed to create player on target node");
275
383
 
276
384
  await this._restorePlayerState(newPlayer, playerState);
277
-
278
- newPlayer.destroy();
385
+
279
386
  if (playerState.current) {
280
387
  newPlayer.queue.add(playerState.current);
281
388
  }
282
-
389
+
283
390
  this.emit("playerMigrated", player, newPlayer, targetNode);
284
391
  return newPlayer;
285
-
392
+
286
393
  } catch (error) {
287
394
  retryCount++;
288
395
  if (retryCount < this.failoverOptions.maxRetries) {
@@ -296,12 +403,12 @@ class Aqua extends EventEmitter {
296
403
 
297
404
  _selectBestNode(availableNodes, player) {
298
405
  if (player.region) {
299
- const regionNode = availableNodes.find(node =>
406
+ const regionNode = availableNodes.find(node =>
300
407
  node.regions?.includes(player.region.toLowerCase())
301
408
  );
302
409
  if (regionNode) return regionNode;
303
410
  }
304
-
411
+
305
412
  return availableNodes[0];
306
413
  }
307
414
 
@@ -316,13 +423,12 @@ class Aqua extends EventEmitter {
316
423
  position: player.position || 0,
317
424
  current: player.current ? { ...player.current } : null,
318
425
  queue: player.queue?.tracks ? [...player.queue.tracks] : [],
319
- repeat: player.repeat,
426
+ repeat: player.loop,
320
427
  shuffle: player.shuffle,
321
428
  deaf: player.deaf || false,
322
429
  mute: player.mute || false,
323
- region: player.region,
324
- requester: player.requester,
325
- timestamp: Date.now()
430
+ timestamp: Date.now(),
431
+ connected: player.connected || false,
326
432
  };
327
433
  } catch (error) {
328
434
  return null;
@@ -347,40 +453,35 @@ class Aqua extends EventEmitter {
347
453
  if (!newPlayer || !playerState) return;
348
454
 
349
455
  try {
350
- // Batch operations where possible
351
456
  const operations = [];
352
-
457
+
353
458
  if (playerState.volume !== undefined) {
354
459
  operations.push(newPlayer.setVolume(playerState.volume));
355
460
  }
356
461
 
357
- // Restore queue efficiently
358
462
  if (playerState.queue?.length > 0) {
359
463
  newPlayer.queue.add(...playerState.queue);
360
464
  }
361
465
 
362
- // Wait for all operations
363
466
  await Promise.all(operations);
364
467
 
365
- // Handle current track restoration
366
468
  if (playerState.current && this.failoverOptions.preservePosition) {
367
469
  newPlayer.queue.unshift(playerState.current);
368
-
470
+
369
471
  if (this.failoverOptions.resumePlayback) {
370
472
  await newPlayer.play();
371
-
473
+
372
474
  if (playerState.position > 0) {
373
- await this._delay(300); // Reduced delay
475
+ await this._delay(300);
374
476
  await newPlayer.seek(playerState.position);
375
477
  }
376
-
478
+
377
479
  if (playerState.paused) {
378
480
  await newPlayer.pause();
379
481
  }
380
482
  }
381
483
  }
382
484
 
383
- // Restore other properties
384
485
  Object.assign(newPlayer, {
385
486
  repeat: playerState.repeat,
386
487
  shuffle: playerState.shuffle
@@ -395,7 +496,6 @@ class Aqua extends EventEmitter {
395
496
  return new Promise(resolve => setTimeout(resolve, ms));
396
497
  }
397
498
 
398
- // Optimized cleanup
399
499
  async cleanupPlayer(player) {
400
500
  if (!player) return;
401
501
  try {
@@ -434,7 +534,6 @@ class Aqua extends EventEmitter {
434
534
  }
435
535
  }
436
536
 
437
- // Optimized sorting with caching
438
537
  const loadCache = new Map();
439
538
  regionNodes.sort((a, b) => {
440
539
  const loadA = loadCache.get(a) ?? (loadCache.set(a, this._calculateLoad(a)), loadCache.get(a));
@@ -469,7 +568,6 @@ class Aqua extends EventEmitter {
469
568
  const player = new Player(this, node, options);
470
569
  this.players.set(options.guildId, player);
471
570
 
472
- // Use pre-bound method for better performance
473
571
  player.once("destroy", this._boundHandlePlayerDestroy);
474
572
  player.connect(options);
475
573
  this.emit("playerCreate", player);
@@ -477,6 +575,10 @@ class Aqua extends EventEmitter {
477
575
  }
478
576
 
479
577
  _handlePlayerDestroy(player) {
578
+ const node = player.nodes;
579
+ if (node && node.players) {
580
+ node.players.delete(player);
581
+ }
480
582
  this.players.delete(player.guildId);
481
583
  this.emit("playerDestroy", player);
482
584
  }
@@ -557,7 +659,7 @@ class Aqua extends EventEmitter {
557
659
  baseResponse.tracks.push(new Track(response.data, requester, requestNode));
558
660
  }
559
661
  break;
560
-
662
+
561
663
  case "playlist": {
562
664
  const info = response.data?.info;
563
665
  if (info) {
@@ -604,42 +706,50 @@ class Aqua extends EventEmitter {
604
706
  }
605
707
  }
606
708
 
607
- // Optimized save/load methods
608
709
  async savePlayer(filePath = "./AquaPlayers.json") {
609
- const data = Array.from(this.players.values(), player => ({
610
- g: player.guildId,
611
- t: player.textChannel,
612
- v: player.voiceChannel,
613
- u: player.current?.uri || null,
614
- p: player.position || 0,
615
- ts: player.timestamp || 0,
616
- q: player.queue?.tracks?.slice(0, 5).map(tr => tr.uri) || [],
617
- r: player.requester || player.current?.requester,
618
- vol: player.volume,
619
- pa: player.paused,
620
- n: player.nodes?.name || null
621
- }));
622
-
710
+ const data = Array.from(this.players.values()).map(player => {
711
+ const requester = player.requester || player.current?.requester;
712
+
713
+ return {
714
+ g: player.guildId,
715
+ t: player.textChannel,
716
+ v: player.voiceChannel,
717
+ u: player.current?.uri || null,
718
+ p: player.position || 0,
719
+ ts: player.timestamp || 0,
720
+ q: player.queue?.tracks?.map(tr => tr.uri).slice(0, 5) || [],
721
+ r: requester ? {
722
+ id: requester.id,
723
+ username: requester.username,
724
+ globalName: requester.globalName,
725
+ discriminator: requester.discriminator,
726
+ avatar: requester.avatar
727
+ } : null,
728
+ vol: player.volume,
729
+ pa: player.paused,
730
+ isPlaying: !!player.current && !player.paused
731
+ };
732
+ });
733
+
623
734
  await fs.writeFile(filePath, JSON.stringify(data), "utf8");
735
+ this.emit("debug", "Aqua", `Saved ${data.length} players to ${filePath}`);
624
736
  }
625
737
 
626
738
  async loadPlayers(filePath = "./AquaPlayers.json") {
627
739
  try {
628
740
  await fs.access(filePath);
629
741
  await this._waitForFirstNode();
630
-
742
+
631
743
  const data = JSON.parse(await fs.readFile(filePath, "utf8"));
632
-
633
- // Process in batches to avoid overwhelming
744
+
634
745
  const batchSize = 5;
635
746
  for (let i = 0; i < data.length; i += batchSize) {
636
747
  const batch = data.slice(i, i + batchSize);
637
748
  await Promise.all(batch.map(p => this._restorePlayer(p)));
638
749
  }
639
-
750
+
640
751
  await fs.writeFile(filePath, "[]", "utf8");
641
752
  } catch (error) {
642
- // Silent fail if file doesn't exist
643
753
  }
644
754
  }
645
755
 
@@ -647,11 +757,11 @@ class Aqua extends EventEmitter {
647
757
  try {
648
758
  let player = this.players.get(p.g);
649
759
  if (!player) {
650
- const targetNode = (p.n && this.nodeMap.get(p.n)?.connected) ?
760
+ const targetNode = (p.n && this.nodeMap.get(p.n)?.connected) ?
651
761
  this.nodeMap.get(p.n) : this.leastUsedNodes[0];
652
-
762
+
653
763
  if (!targetNode) return;
654
-
764
+
655
765
  player = await this.createConnection({
656
766
  guildId: p.g,
657
767
  textChannel: p.t,
@@ -661,7 +771,6 @@ class Aqua extends EventEmitter {
661
771
  });
662
772
  }
663
773
 
664
- // Restore current track
665
774
  if (p.u && player) {
666
775
  const resolved = await this.resolve({ query: p.u, requester: p.r });
667
776
  if (resolved.tracks?.[0]) {
@@ -670,13 +779,12 @@ class Aqua extends EventEmitter {
670
779
  if (typeof p.ts === "number") player.timestamp = p.ts;
671
780
  }
672
781
  }
673
-
674
- // Restore queue
782
+
675
783
  if (p.q?.length && player) {
676
784
  const queuePromises = p.q
677
785
  .filter(uri => uri !== p.u)
678
786
  .map(uri => this.resolve({ query: uri, requester: p.r }));
679
-
787
+
680
788
  const queueResults = await Promise.allSettled(queuePromises);
681
789
  queueResults.forEach(result => {
682
790
  if (result.status === 'fulfilled' && result.value.tracks?.[0]) {
@@ -684,21 +792,20 @@ class Aqua extends EventEmitter {
684
792
  }
685
793
  });
686
794
  }
687
-
795
+
688
796
  if (player) {
689
797
  player.paused = !!p.pa;
690
- if (!player.playing && !player.paused && player.queue.size > 0) {
798
+ if ((p.isPlaying || (p.pa && p.u)) && player.queue.size > 0) {
691
799
  player.play();
692
800
  }
693
801
  }
694
802
  } catch (error) {
695
- // Silent fail for individual player restoration
696
803
  }
697
804
  }
698
805
 
699
806
  async _waitForFirstNode() {
700
807
  if (this.leastUsedNodes.length > 0) return;
701
-
808
+
702
809
  return new Promise(resolve => {
703
810
  const checkInterval = setInterval(() => {
704
811
  if (this.leastUsedNodes.length > 0) {
@@ -709,6 +816,44 @@ class Aqua extends EventEmitter {
709
816
  });
710
817
  }
711
818
 
819
+ // Auto-resume utility methods
820
+ getBrokenPlayersCount() {
821
+ return this._brokenPlayers.size;
822
+ }
823
+
824
+ getBrokenPlayers() {
825
+ return Array.from(this._brokenPlayers.entries()).map(([guildId, state]) => ({
826
+ guildId,
827
+ originalNodeId: state.originalNodeId,
828
+ brokenAt: state.brokenAt,
829
+ hasCurrentTrack: !!state.current,
830
+ queueSize: state.queue?.length || 0
831
+ }));
832
+ }
833
+
834
+ clearBrokenPlayers() {
835
+ this._brokenPlayers.clear();
836
+ }
837
+
838
+ async forceBrokenPlayerRebuild(guildId) {
839
+ const brokenState = this._brokenPlayers.get(guildId);
840
+ if (!brokenState) return false;
841
+
842
+ try {
843
+ const targetNode = this.nodeMap.get(brokenState.originalNodeId) || this.leastUsedNodes[0];
844
+ if (!targetNode || !targetNode.connected) {
845
+ throw new Error("No available nodes for rebuild");
846
+ }
847
+
848
+ await this._rebuildPlayer(brokenState, targetNode);
849
+ this._brokenPlayers.delete(guildId);
850
+ return true;
851
+ } catch (error) {
852
+ this.emit("error", null, new Error(`Failed to force rebuild player for guild ${guildId}: ${error.message}`));
853
+ return false;
854
+ }
855
+ }
856
+
712
857
  // Utility methods
713
858
  resetFailoverAttempts(nodeId) {
714
859
  this._failoverQueue.delete(nodeId);
@@ -747,15 +892,15 @@ class Aqua extends EventEmitter {
747
892
  }
748
893
  return stats;
749
894
  }
750
-
895
+
751
896
  async forceFailover(nodeIdentifier) {
752
897
  const node = this.nodeMap.get(nodeIdentifier);
753
898
  if (!node) return;
754
-
899
+
755
900
  if (node.connected) {
756
901
  await node.destroy();
757
902
  }
758
-
903
+
759
904
  this._cleanupNode(nodeIdentifier);
760
905
  }
761
906
  }
@@ -52,7 +52,11 @@ class Node {
52
52
  this.reconnectAttempted = 0;
53
53
  this.reconnectTimeoutId = null;
54
54
  this.isDestroyed = false;
55
- this.lastHealthCheck = Date.now();
55
+
56
+ this._onOpen = this._onOpen.bind(this);
57
+ this._onError = this._onError.bind(this);
58
+ this._onMessage = this._onMessage.bind(this);
59
+ this._onClose = this._onClose.bind(this);
56
60
 
57
61
  this._headers = this._constructHeaders();
58
62
  this.initializeStats();
@@ -87,7 +91,6 @@ class Node {
87
91
  async _onOpen() {
88
92
  this.connected = true;
89
93
  this.reconnectAttempted = 0;
90
- this.lastHealthCheck = Date.now();
91
94
  this.aqua.emit("debug", this.name, "WebSocket connection established");
92
95
 
93
96
  if (this.aqua.bypassChecks?.nodeFetchInfo) return;
@@ -118,30 +121,26 @@ class Node {
118
121
  return;
119
122
  }
120
123
 
121
- const op = payload?.op;
124
+ const { op, guildId } = payload;
122
125
  if (!op) return;
123
126
 
124
- this.lastHealthCheck = Date.now();
125
-
126
- if (op === "stats") {
127
- this._updateStats(payload);
128
- return;
129
- }
130
- if (op === "ready") {
131
- this._handleReadyOp(payload);
132
- return;
133
- }
134
127
 
135
- if (op.startsWith("Lyrics")) {
136
- const player = payload.guildId ? this.aqua.players.get(payload.guildId) : null;
137
- const track = payload.track || null;
138
- this.aqua.emit(op, player, track, payload);
139
- return;
140
- }
141
-
142
- if (payload.guildId) {
143
- const player = this.aqua.players.get(payload.guildId);
144
- if (player) player.emit(op, payload);
128
+ switch (op) {
129
+ case "stats":
130
+ this._updateStats(payload);
131
+ break;
132
+ case "ready":
133
+ this._handleReadyOp(payload);
134
+ break;
135
+ default:
136
+ if (op.startsWith("Lyrics")) {
137
+ const player = guildId ? this.aqua.players.get(guildId) : null;
138
+ this.aqua.emit(op, player, payload.track || null, payload);
139
+ } else if (guildId) {
140
+ const player = this.aqua.players.get(guildId);
141
+ player?.emit(op, payload);
142
+ }
143
+ break;
145
144
  }
146
145
  }
147
146
 
@@ -202,7 +201,7 @@ class Node {
202
201
 
203
202
  async connect() {
204
203
  if (this.isDestroyed) return;
205
-
204
+
206
205
  if (this.ws && this.ws.readyState === Node.WS_OPEN) {
207
206
  this.aqua.emit("debug", this.name, "WebSocket already connected");
208
207
  return;
@@ -215,10 +214,11 @@ class Node {
215
214
  perMessageDeflate: false
216
215
  });
217
216
 
218
- this.ws.once("open", this._onOpen.bind(this));
219
- this.ws.once("error", this._onError.bind(this));
220
- this.ws.on("message", this._onMessage.bind(this));
221
- this.ws.once("close", this._onClose.bind(this));
217
+ this.ws.once("open", this._onOpen);
218
+ this.ws.once("error", this._onError);
219
+ this.ws.on("message", this._onMessage);
220
+ this.ws.once("close", this._onClose);
221
+
222
222
  }
223
223
 
224
224
  cleanupExistingConnection() {
@@ -264,17 +264,17 @@ class Node {
264
264
  this.stats.playingPlayers = newStats.playingPlayers ?? this.stats.playingPlayers;
265
265
  this.stats.uptime = newStats.uptime ?? this.stats.uptime;
266
266
  this.stats.ping = newStats.ping ?? this.stats.ping;
267
-
267
+
268
268
  if (newStats.memory) {
269
269
  Object.assign(this.stats.memory, newStats.memory);
270
270
  this._calculateMemoryPercentages();
271
271
  }
272
-
272
+
273
273
  if (newStats.cpu) {
274
274
  Object.assign(this.stats.cpu, newStats.cpu);
275
275
  this._calculateCpuPercentages();
276
276
  }
277
-
277
+
278
278
  if (newStats.frameStats) {
279
279
  Object.assign(this.stats.frameStats, newStats.frameStats);
280
280
  }
@@ -458,7 +458,7 @@ class Player extends EventEmitter {
458
458
  try {
459
459
  await this.nowPlayingMessage.delete();
460
460
  } catch (error) {
461
- console.error("Error deleting now playing message:", error);
461
+ // Ignore
462
462
  } finally {
463
463
  this.nowPlayingMessage = null;
464
464
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aqualink",
3
- "version": "2.7.0",
3
+ "version": "2.7.2",
4
4
  "description": "An Lavalink client, focused in pure performance and features",
5
5
  "main": "build/index.js",
6
6
  "types": "index.d.ts",
@@ -42,7 +42,6 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "ws": "^8.18.3",
45
- "fs-extra": "^11.3.0",
46
45
  "tseep": "^1.3.1"
47
46
  },
48
47
  "maintainers": [