aqualink 2.7.2 → 2.7.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.
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
 
3
+ const REGION_REGEX = /^([a-z]+)/;
4
+
3
5
  class Connection {
4
6
  constructor(player) {
5
7
  this.player = player;
@@ -20,51 +22,75 @@ class Connection {
20
22
  if (!data?.endpoint) return;
21
23
 
22
24
  const { endpoint, token } = data;
23
- const newRegion = endpoint.split('.')[0];
24
- if (!newRegion) return;
25
-
26
- if (this.region !== newRegion) {
27
- const oldRegion = this.region;
28
- this.endpoint = endpoint;
29
- this.token = token;
30
- this.region = newRegion;
31
-
32
- this.aqua.emit(
33
- "debug",
34
- `[Player ${this.guildId} - CONNECTION] Voice Server: ${
35
- oldRegion ? `Changed from ${oldRegion} to ${newRegion}` : newRegion
36
- }`
37
- );
25
+
26
+ const regionMatch = REGION_REGEX.exec(endpoint);
27
+ if (!regionMatch) return;
28
+
29
+ const newRegion = regionMatch[1];
30
+
31
+ if (this.endpoint === endpoint && this.token === token && this.region === newRegion) {
32
+ return;
33
+ }
38
34
 
39
- this._updatePlayerVoiceData();
35
+ const oldRegion = this.region;
36
+ this.endpoint = endpoint;
37
+ this.token = token;
38
+ this.region = newRegion;
39
+
40
+ this.aqua.emit("debug",
41
+ `[Player ${this.guildId} - CONNECTION] Voice Server: ${oldRegion ? `Changed from ${oldRegion} to ${newRegion}` : newRegion}`
42
+ );
43
+
44
+ if (this.player.paused) {
45
+ this.player.paused = false;
40
46
  }
47
+
48
+ this._updatePlayerVoiceData();
41
49
  }
42
50
 
43
51
  setStateUpdate(data) {
44
52
  if (!data) {
45
- this.player?.destroy();
53
+ this._destroyPlayer();
46
54
  return;
47
55
  }
48
56
 
49
57
  const { channel_id, session_id, self_deaf, self_mute } = data;
58
+
50
59
  if (!channel_id || !session_id) {
51
- this.player?.destroy();
60
+ this._destroyPlayer();
52
61
  return;
53
62
  }
54
63
 
55
64
  if (this.voiceChannel !== channel_id) {
56
65
  this.aqua.emit("playerMove", this.voiceChannel, channel_id);
57
66
  this.voiceChannel = channel_id;
67
+ this.player.voiceChannel = channel_id;
58
68
  }
59
69
 
60
- this.selfDeaf = Boolean(self_deaf);
61
- this.selfMute = Boolean(self_mute);
62
- this.sessionId = session_id;
70
+ this.selfDeaf = !!self_deaf;
71
+ this.selfMute = !!self_mute;
72
+
73
+ if (this.sessionId !== session_id) {
74
+ this.sessionId = session_id;
75
+ this._updatePlayerVoiceData();
76
+ }
77
+ }
78
+
79
+ _destroyPlayer() {
80
+ if (this.player) {
81
+ this.player.destroy();
82
+ this.aqua.emit("playerDestroy", this.player);
83
+ }
63
84
  }
64
85
 
65
86
  _updatePlayerVoiceData() {
66
87
  if (!this.player) return;
67
88
 
89
+ if (!this.sessionId || !this.endpoint || !this.token) {
90
+ this.aqua.emit("debug", `[Player ${this.guildId}] Incomplete voice data, waiting for complete data`);
91
+ return;
92
+ }
93
+
68
94
  const voiceData = {
69
95
  sessionId: this.sessionId,
70
96
  endpoint: this.endpoint,
@@ -87,6 +113,7 @@ class Connection {
87
113
  });
88
114
  }
89
115
  }
116
+
90
117
  }
91
118
 
92
- module.exports = Connection;
119
+ module.exports = Connection;
@@ -18,14 +18,14 @@ const EVENT_HANDLERS = Object.freeze({
18
18
  TrackChangeEvent: "trackChange",
19
19
  WebSocketClosedEvent: "socketClosed",
20
20
  LyricsLineEvent: "lyricsLine",
21
- LyricsFoundEvent: "lyricsFound" ,
21
+ LyricsFoundEvent: "lyricsFound",
22
22
  LyricsNotFoundEvent: "lyricsNotFound"
23
23
  });
24
24
 
25
25
 
26
26
  const VALID_MODES = new Set(Object.values(LOOP_MODES));
27
27
  const FAILURE_REASONS = new Set(["LOAD_FAILED", "CLEANUP"]);
28
- const RECONNECT_CODES = new Set([4015, 4009]);
28
+ const RECONNECT_CODES = new Set([4015, 4009, 4006, 1000]);
29
29
  const FAIL_LOAD_TYPES = new Set(["error", "empty", "LOAD_FAILED", "NO_MATCHES"]);
30
30
 
31
31
  class UpdateBatcher {
@@ -94,7 +94,7 @@ class Player extends EventEmitter {
94
94
 
95
95
  const vol = options.defaultVolume ?? 100;
96
96
  this.volume = vol < 0 ? 0 : vol > 200 ? 200 : vol;
97
-
97
+
98
98
  this.loop = VALID_MODES.has(options.loop) ? options.loop : LOOP_MODES.NONE;
99
99
  this.shouldDeleteMessage = Boolean(this.aqua.options.shouldDeleteMessage);
100
100
  this.leaveOnEnd = Boolean(this.aqua.options.leaveOnEnd);
@@ -135,6 +135,8 @@ class Player extends EventEmitter {
135
135
  async _handleEvent(payload) {
136
136
  try {
137
137
  const handlerName = EVENT_HANDLERS[payload.type];
138
+
139
+ console.log(`Event: ${payload.type} for Player ${handlerName}`);
138
140
  if (handlerName && typeof this[handlerName] === "function") {
139
141
  await this[handlerName](this, this.current, payload);
140
142
  } else {
@@ -249,47 +251,47 @@ class Player extends EventEmitter {
249
251
  return this;
250
252
  }
251
253
 
252
- destroy() {
253
- if (!this.connected) return this;
254
+ destroy() {
255
+ if (!this.connected) return this;
254
256
 
255
- const voiceChannelId = this.voiceChannel ? this.voiceChannel.id || this.voiceChannel : null;
256
- this._updateBatcher.destroy();
257
+ const voiceChannelId = this.voiceChannel ? this.voiceChannel.id || this.voiceChannel : null;
258
+ this._updateBatcher.destroy();
257
259
 
258
- this.send({ guild_id: this.guildId, channel_id: null });
259
- this._lastVoiceChannel = voiceChannelId;
260
- this.voiceChannel = null;
261
- this.connected = false;
262
- this.send({ guild_id: this.guildId, channel_id: null });
260
+ this.send({ guild_id: this.guildId, channel_id: null });
261
+ this._lastVoiceChannel = voiceChannelId;
262
+ this.voiceChannel = null;
263
+ this.connected = false;
264
+ this.send({ guild_id: this.guildId, channel_id: null });
263
265
 
264
- if (this.nowPlayingMessage) {
265
- this.nowPlayingMessage.delete().catch(() => { });
266
- this.nowPlayingMessage = null;
267
- }
266
+ if (this.nowPlayingMessage) {
267
+ this.nowPlayingMessage.delete().catch(() => { });
268
+ this.nowPlayingMessage = null;
269
+ }
268
270
 
269
- this.isAutoplay = false;
270
- this.aqua.destroyPlayer(this.guildId);
271
-
272
- if (this.nodes?.connected) {
273
- try {
274
- this.nodes.rest.destroyPlayer(this.guildId);
275
- } catch (error) {
276
- if (!error.message.includes('ECONNREFUSED')) {
277
- console.error('Error destroying player on node:', error);
271
+ this.isAutoplay = false;
272
+ this.aqua.destroyPlayer(this.guildId);
273
+
274
+ if (this.nodes?.connected) {
275
+ try {
276
+ this.nodes.rest.destroyPlayer(this.guildId);
277
+ } catch (error) {
278
+ if (!error.message.includes('ECONNREFUSED')) {
279
+ console.error('Error destroying player on node:', error);
280
+ }
278
281
  }
279
282
  }
280
- }
281
-
282
- this.previousTracksCount = 0;
283
- this._dataStore.clear();
284
- this.removeAllListeners();
285
283
 
286
- this.queue = null;
287
- this.previousTracks = null;
288
- this.connection = null;
289
- this.filters = null;
284
+ this.previousTracksCount = 0;
285
+ this._dataStore.clear();
286
+ this.removeAllListeners();
290
287
 
291
- return this;
292
- }
288
+ this.queue = null;
289
+ this.previousTracks = null;
290
+ this.connection = null;
291
+ this.filters = null;
292
+
293
+ return this;
294
+ }
293
295
 
294
296
  pause(paused) {
295
297
  if (this.paused === paused) return this;
@@ -335,16 +337,16 @@ class Player extends EventEmitter {
335
337
  return this.nodes.rest.unsubscribeLiveLyrics(this.guildId);
336
338
  }
337
339
 
338
- seek(position) {
339
- if (!this.playing) return this;
340
- if (position < 0) position = 0;
341
- if (this.current?.info?.length && position > this.current.info.length) {
342
- position = this.current.info.length;
340
+ seek(position) {
341
+ if (!this.playing) return this;
342
+ if (position < 0) position = 0;
343
+ if (this.current?.info?.length && position > this.current.info.length) {
344
+ position = this.current.info.length;
345
+ }
346
+ this.position = position;
347
+ this.batchUpdatePlayer({ position: this.position });
348
+ return this;
343
349
  }
344
- this.position = position;
345
- this.batchUpdatePlayer({ position: this.position });
346
- return this;
347
- }
348
350
 
349
351
  stop() {
350
352
  if (!this.playing) return this;
@@ -400,7 +402,7 @@ class Player extends EventEmitter {
400
402
  shuffle() {
401
403
  const queue = this.queue;
402
404
  const len = queue.length;
403
-
405
+
404
406
  if (len <= 1) return this;
405
407
 
406
408
  if (len < 200) {
@@ -411,18 +413,18 @@ class Player extends EventEmitter {
411
413
  } else {
412
414
  this._shuffleAsync(queue, len - 1);
413
415
  }
414
-
416
+
415
417
  return this;
416
418
  }
417
419
 
418
420
  _shuffleAsync(queue, i, chunkSize = 100) {
419
421
  const end = Math.max(0, i - chunkSize);
420
-
422
+
421
423
  for (; i > end; i--) {
422
424
  const j = Math.floor(Math.random() * (i + 1));
423
425
  [queue[i], queue[j]] = [queue[j], queue[i]];
424
426
  }
425
-
427
+
426
428
  if (i > 0) {
427
429
  setImmediate(() => this._shuffleAsync(queue, i, chunkSize));
428
430
  }
@@ -512,19 +514,58 @@ class Player extends EventEmitter {
512
514
  return this.stop();
513
515
  }
514
516
 
515
- async socketClosed(player, payload) {
516
- const { code, guildId } = payload || {};
517
+ async socketClosed(player, track, payload) {
518
+ const { code, guildId, reason } = payload || {};
519
+
517
520
  if (RECONNECT_CODES.has(code)) {
518
- this.send({
519
- guild_id: guildId,
520
- channel_id: this.voiceChannel,
521
- self_mute: this.mute,
522
- self_deaf: this.deaf
523
- });
521
+ try {
522
+ this.connected = false;
523
+
524
+ const voiceChannelId = this.voiceChannel?.id || this.voiceChannel;
525
+
526
+ if (!voiceChannelId) {
527
+ console.error(`Cannot reconnect: No voice channel available for guild ${guildId}`);
528
+ this.aqua.emit("socketClosed", player, payload);
529
+ return;
530
+ }
531
+
532
+ this.aqua.emit("debug", guildId, `Attempting to reconnect to voice channel: ${voiceChannelId}`);
533
+
534
+ this.send({
535
+ guild_id: guildId,
536
+ channel_id: voiceChannelId,
537
+ self_mute: this.mute || false,
538
+ self_deaf: this.deaf || true
539
+ });
540
+
541
+ setTimeout(() => {
542
+ if (!this.connected) {
543
+ console.error(`Reconnection failed for guild ${guildId} after timeout`);
544
+ this.aqua.emit("socketClosed", player, payload);
545
+ }
546
+ }, 5000);
547
+
548
+ this.aqua.emit("debug", guildId, `Reconnection attempt sent for voice channel: ${voiceChannelId}`);
549
+ return;
550
+
551
+ } catch (error) {
552
+ console.error(`Failed to reconnect socket for guild ${guildId}:`, error);
553
+ this.connected = false;
554
+ }
524
555
  }
556
+
557
+ this.connected = false;
525
558
  this.aqua.emit("socketClosed", player, payload);
526
- this.pause(true);
527
- this.aqua.emit("debug", this.guildId, "Player paused due to socket closure.");
559
+
560
+ if (this.playing && this.current && this.queue.length > 0) {
561
+ try {
562
+ this.aqua.emit("debug", guildId, "Attempting to resume playback after socket close");
563
+ await this.play();
564
+ } catch (error) {
565
+ console.error(`Failed to resume playback after socket close for guild ${guildId}:`, error);
566
+ this.stop();
567
+ }
568
+ }
528
569
  }
529
570
 
530
571
  async lyricsLine(player, track, payload) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aqualink",
3
- "version": "2.7.2",
3
+ "version": "2.7.3",
4
4
  "description": "An Lavalink client, focused in pure performance and features",
5
5
  "main": "build/index.js",
6
6
  "types": "index.d.ts",