aqualink 2.7.2 → 2.7.3-hotfix
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/build/structures/Connection.js +49 -22
- package/build/structures/Player.js +98 -59
- package/package.json +1 -1
|
@@ -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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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 =
|
|
61
|
-
this.selfMute =
|
|
62
|
-
|
|
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);
|
|
@@ -249,47 +249,47 @@ class Player extends EventEmitter {
|
|
|
249
249
|
return this;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
destroy() {
|
|
253
|
+
if (!this.connected) return this;
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
const voiceChannelId = this.voiceChannel ? this.voiceChannel.id || this.voiceChannel : null;
|
|
256
|
+
this._updateBatcher.destroy();
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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 });
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
if (this.nowPlayingMessage) {
|
|
265
|
+
this.nowPlayingMessage.delete().catch(() => { });
|
|
266
|
+
this.nowPlayingMessage = null;
|
|
267
|
+
}
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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);
|
|
278
|
+
}
|
|
278
279
|
}
|
|
279
280
|
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
this.previousTracksCount = 0;
|
|
283
|
-
this._dataStore.clear();
|
|
284
|
-
this.removeAllListeners();
|
|
285
281
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
this.filters = null;
|
|
282
|
+
this.previousTracksCount = 0;
|
|
283
|
+
this._dataStore.clear();
|
|
284
|
+
this.removeAllListeners();
|
|
290
285
|
|
|
291
|
-
|
|
292
|
-
|
|
286
|
+
this.queue = null;
|
|
287
|
+
this.previousTracks = null;
|
|
288
|
+
this.connection = null;
|
|
289
|
+
this.filters = null;
|
|
290
|
+
|
|
291
|
+
return this;
|
|
292
|
+
}
|
|
293
293
|
|
|
294
294
|
pause(paused) {
|
|
295
295
|
if (this.paused === paused) return this;
|
|
@@ -335,16 +335,16 @@ class Player extends EventEmitter {
|
|
|
335
335
|
return this.nodes.rest.unsubscribeLiveLyrics(this.guildId);
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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;
|
|
343
|
+
}
|
|
344
|
+
this.position = position;
|
|
345
|
+
this.batchUpdatePlayer({ position: this.position });
|
|
346
|
+
return this;
|
|
343
347
|
}
|
|
344
|
-
this.position = position;
|
|
345
|
-
this.batchUpdatePlayer({ position: this.position });
|
|
346
|
-
return this;
|
|
347
|
-
}
|
|
348
348
|
|
|
349
349
|
stop() {
|
|
350
350
|
if (!this.playing) return this;
|
|
@@ -400,7 +400,7 @@ class Player extends EventEmitter {
|
|
|
400
400
|
shuffle() {
|
|
401
401
|
const queue = this.queue;
|
|
402
402
|
const len = queue.length;
|
|
403
|
-
|
|
403
|
+
|
|
404
404
|
if (len <= 1) return this;
|
|
405
405
|
|
|
406
406
|
if (len < 200) {
|
|
@@ -411,18 +411,18 @@ class Player extends EventEmitter {
|
|
|
411
411
|
} else {
|
|
412
412
|
this._shuffleAsync(queue, len - 1);
|
|
413
413
|
}
|
|
414
|
-
|
|
414
|
+
|
|
415
415
|
return this;
|
|
416
416
|
}
|
|
417
417
|
|
|
418
418
|
_shuffleAsync(queue, i, chunkSize = 100) {
|
|
419
419
|
const end = Math.max(0, i - chunkSize);
|
|
420
|
-
|
|
420
|
+
|
|
421
421
|
for (; i > end; i--) {
|
|
422
422
|
const j = Math.floor(Math.random() * (i + 1));
|
|
423
423
|
[queue[i], queue[j]] = [queue[j], queue[i]];
|
|
424
424
|
}
|
|
425
|
-
|
|
425
|
+
|
|
426
426
|
if (i > 0) {
|
|
427
427
|
setImmediate(() => this._shuffleAsync(queue, i, chunkSize));
|
|
428
428
|
}
|
|
@@ -512,19 +512,58 @@ class Player extends EventEmitter {
|
|
|
512
512
|
return this.stop();
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
-
async socketClosed(player, payload) {
|
|
516
|
-
const { code, guildId } = payload || {};
|
|
515
|
+
async socketClosed(player, track, payload) {
|
|
516
|
+
const { code, guildId, reason } = payload || {};
|
|
517
|
+
|
|
517
518
|
if (RECONNECT_CODES.has(code)) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
519
|
+
try {
|
|
520
|
+
this.connected = false;
|
|
521
|
+
|
|
522
|
+
const voiceChannelId = this.voiceChannel?.id || this.voiceChannel;
|
|
523
|
+
|
|
524
|
+
if (!voiceChannelId) {
|
|
525
|
+
console.error(`Cannot reconnect: No voice channel available for guild ${guildId}`);
|
|
526
|
+
this.aqua.emit("socketClosed", player, payload);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
this.aqua.emit("debug", guildId, `Attempting to reconnect to voice channel: ${voiceChannelId}`);
|
|
531
|
+
|
|
532
|
+
this.send({
|
|
533
|
+
guild_id: guildId,
|
|
534
|
+
channel_id: voiceChannelId,
|
|
535
|
+
self_mute: this.mute || false,
|
|
536
|
+
self_deaf: this.deaf || true
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
setTimeout(() => {
|
|
540
|
+
if (!this.connected) {
|
|
541
|
+
console.error(`Reconnection failed for guild ${guildId} after timeout`);
|
|
542
|
+
this.aqua.emit("socketClosed", player, payload);
|
|
543
|
+
}
|
|
544
|
+
}, 5000);
|
|
545
|
+
|
|
546
|
+
this.aqua.emit("debug", guildId, `Reconnection attempt sent for voice channel: ${voiceChannelId}`);
|
|
547
|
+
return;
|
|
548
|
+
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.error(`Failed to reconnect socket for guild ${guildId}:`, error);
|
|
551
|
+
this.connected = false;
|
|
552
|
+
}
|
|
524
553
|
}
|
|
554
|
+
|
|
555
|
+
this.connected = false;
|
|
525
556
|
this.aqua.emit("socketClosed", player, payload);
|
|
526
|
-
|
|
527
|
-
this.
|
|
557
|
+
|
|
558
|
+
if (this.playing && this.current && this.queue.length > 0) {
|
|
559
|
+
try {
|
|
560
|
+
this.aqua.emit("debug", guildId, "Attempting to resume playback after socket close");
|
|
561
|
+
await this.play();
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error(`Failed to resume playback after socket close for guild ${guildId}:`, error);
|
|
564
|
+
this.stop();
|
|
565
|
+
}
|
|
566
|
+
}
|
|
528
567
|
}
|
|
529
568
|
|
|
530
569
|
async lyricsLine(player, track, payload) {
|