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.
- package/build/structures/Connection.js +49 -22
- package/build/structures/Player.js +100 -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);
|
|
@@ -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
|
-
|
|
253
|
-
|
|
254
|
+
destroy() {
|
|
255
|
+
if (!this.connected) return this;
|
|
254
256
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
+
const voiceChannelId = this.voiceChannel ? this.voiceChannel.id || this.voiceChannel : null;
|
|
258
|
+
this._updateBatcher.destroy();
|
|
257
259
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
266
|
+
if (this.nowPlayingMessage) {
|
|
267
|
+
this.nowPlayingMessage.delete().catch(() => { });
|
|
268
|
+
this.nowPlayingMessage = null;
|
|
269
|
+
}
|
|
268
270
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
this.filters = null;
|
|
284
|
+
this.previousTracksCount = 0;
|
|
285
|
+
this._dataStore.clear();
|
|
286
|
+
this.removeAllListeners();
|
|
290
287
|
|
|
291
|
-
|
|
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
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
-
|
|
527
|
-
this.
|
|
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) {
|