aqualink 2.3.0 → 2.3.1
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/handlers/autoplay.js +79 -59
- package/build/structures/Player.js +66 -62
- package/package.json +1 -1
|
@@ -1,95 +1,115 @@
|
|
|
1
1
|
const https = require('https');
|
|
2
|
+
const crypto = require('crypto');
|
|
2
3
|
|
|
3
|
-
function
|
|
4
|
+
function quickFetch(url, options = {}) {
|
|
4
5
|
return new Promise((resolve, reject) => {
|
|
5
|
-
const req = https.get(url, options,
|
|
6
|
+
const req = https.get(url, options, res => {
|
|
6
7
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
7
|
-
return
|
|
8
|
+
return resolve(quickFetch(res.headers.location, options));
|
|
8
9
|
}
|
|
9
|
-
|
|
10
10
|
if (res.statusCode !== 200) {
|
|
11
|
-
res.resume();
|
|
12
|
-
reject(new Error(`Request failed. Status code: ${res.statusCode}`));
|
|
13
|
-
return;
|
|
11
|
+
res.resume();
|
|
12
|
+
return reject(new Error(`Request failed. Status code: ${res.statusCode}`));
|
|
14
13
|
}
|
|
15
|
-
|
|
16
14
|
const chunks = [];
|
|
17
15
|
res.on('data', chunk => chunks.push(chunk));
|
|
18
16
|
res.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
19
17
|
});
|
|
20
|
-
|
|
18
|
+
req.on('error', reject);
|
|
21
19
|
req.setTimeout(10000, () => {
|
|
22
20
|
req.destroy();
|
|
23
21
|
reject(new Error('Request timeout'));
|
|
24
22
|
});
|
|
25
|
-
|
|
26
|
-
req.on('error', err => {
|
|
27
|
-
reject(err);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
23
|
req.end();
|
|
31
24
|
});
|
|
32
25
|
}
|
|
33
26
|
|
|
34
|
-
async function
|
|
27
|
+
async function soundAutoPlay(baseUrl) {
|
|
35
28
|
try {
|
|
36
|
-
const html = await
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const hrefs = new Set();
|
|
29
|
+
const html = await quickFetch(`${baseUrl}/recommended`);
|
|
30
|
+
const regex = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g;
|
|
31
|
+
const links = new Set();
|
|
40
32
|
let match;
|
|
41
|
-
|
|
42
33
|
while ((match = regex.exec(html)) !== null) {
|
|
43
|
-
|
|
34
|
+
links.add(`https://soundcloud.com${match[1]}`);
|
|
44
35
|
}
|
|
45
|
-
|
|
46
|
-
if (hrefs.size === 0) {
|
|
36
|
+
if (!links.size) {
|
|
47
37
|
throw new Error("No recommended tracks found on SoundCloud.");
|
|
48
38
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
for (let i = shuffledHrefs.length - 1; i > 0; i--) {
|
|
39
|
+
const urls = Array.from(links);
|
|
40
|
+
for (let i = urls.length - 1; i > 0; i--) {
|
|
52
41
|
const j = Math.floor(Math.random() * (i + 1));
|
|
53
|
-
[
|
|
42
|
+
[urls[i], urls[j]] = [urls[j], urls[i]];
|
|
54
43
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.error("Error fetching SoundCloud recommendations:", error);
|
|
44
|
+
return urls;
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error("Error in SoundCloud autoplay:", err);
|
|
59
47
|
return [];
|
|
60
48
|
}
|
|
61
49
|
}
|
|
62
50
|
|
|
63
|
-
|
|
51
|
+
function gerenateToKen() {
|
|
52
|
+
const totpSecret = Buffer.from(new Uint8Array([
|
|
53
|
+
53, 53, 48, 55, 49, 52, 53, 56, 53, 51, 52, 56, 55, 52, 57, 57,
|
|
54
|
+
53, 57, 50, 50, 52, 56, 54, 51, 48, 51, 50, 57, 51, 52, 55
|
|
55
|
+
]));
|
|
56
|
+
|
|
57
|
+
// Note for me: Can also be used from Buffer.from("5507145853487499592248630329347", 'utf8');
|
|
58
|
+
|
|
59
|
+
const timeStep = Math.floor(Date.now() / 30000);
|
|
60
|
+
const counter = Buffer.alloc(8);
|
|
61
|
+
counter.writeBigInt64BE(BigInt(timeStep));
|
|
62
|
+
|
|
63
|
+
const hmac = crypto.createHmac('sha1', totpSecret);
|
|
64
|
+
hmac.update(counter);
|
|
65
|
+
const hash = hmac.digest();
|
|
66
|
+
const offset = hash[hash.length - 1] & 0x0f;
|
|
67
|
+
const binCode =
|
|
68
|
+
((hash[offset] & 0x7f) << 24) |
|
|
69
|
+
((hash[offset + 1] & 0xff) << 16) |
|
|
70
|
+
((hash[offset + 2] & 0xff) << 8) |
|
|
71
|
+
(hash[offset + 3] & 0xff);
|
|
72
|
+
const token = (binCode % 1000000).toString().padStart(6, '0');
|
|
73
|
+
return [token, timeStep * 30000];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function spotifyAutoPlay(seedTrackId) {
|
|
77
|
+
const [totp, ts] = gerenateToKen();
|
|
78
|
+
const params = new URLSearchParams({
|
|
79
|
+
reason: "transport",
|
|
80
|
+
productType: "embed",
|
|
81
|
+
totp,
|
|
82
|
+
totpVer: "5",
|
|
83
|
+
ts: ts.toString()
|
|
84
|
+
});
|
|
85
|
+
const tokenUrl = `https://open.spotify.com/get_access_token?${params.toString()}`;
|
|
86
|
+
const tokenData = await quickFetch(tokenUrl);
|
|
87
|
+
|
|
88
|
+
let accessToken;
|
|
64
89
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
Authorization: `Bearer ${accessToken}`,
|
|
76
|
-
'Content-Type': 'application/json'
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
const data = JSON.parse(recommendationsResponse);
|
|
82
|
-
const tracks = data?.tracks || [];
|
|
83
|
-
|
|
84
|
-
if (tracks.length === 0) {
|
|
85
|
-
throw new Error("No recommended tracks found on Spotify.");
|
|
90
|
+
accessToken = JSON.parse(tokenData).accessToken;
|
|
91
|
+
} catch {
|
|
92
|
+
throw new Error("Failed to retrieve Spotify access token.");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const recUrl = `https://api.spotify.com/v1/recommendations?limit=10&seed_tracks=${seedTrackId}`;
|
|
96
|
+
const recData = await quickFetch(recUrl, {
|
|
97
|
+
headers: {
|
|
98
|
+
Authorization: `Bearer ${accessToken}`,
|
|
99
|
+
'Content-Type': 'application/json'
|
|
86
100
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
let tracks;
|
|
104
|
+
try {
|
|
105
|
+
tracks = JSON.parse(recData).tracks;
|
|
106
|
+
} catch {
|
|
107
|
+
throw new Error("Failed to parse Spotify recommendations.");
|
|
92
108
|
}
|
|
109
|
+
return tracks[Math.floor(Math.random() * tracks.length)].id;
|
|
93
110
|
}
|
|
94
111
|
|
|
95
|
-
module.exports = {
|
|
112
|
+
module.exports = {
|
|
113
|
+
scAutoPlay: soundAutoPlay,
|
|
114
|
+
spAutoPlay: spotifyAutoPlay
|
|
115
|
+
};
|
|
@@ -26,24 +26,24 @@ class Player extends EventEmitter {
|
|
|
26
26
|
|
|
27
27
|
constructor(aqua, nodes, options = {}) {
|
|
28
28
|
super();
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
this.aqua = aqua;
|
|
31
31
|
this.nodes = nodes;
|
|
32
32
|
this.guildId = options.guildId;
|
|
33
33
|
this.textChannel = options.textChannel;
|
|
34
34
|
this.voiceChannel = options.voiceChannel;
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
this.connection = new Connection(this);
|
|
37
37
|
this.filters = new Filters(this);
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
this.volume = Math.max(0, Math.min(options.defaultVolume ?? 100, 200));
|
|
40
40
|
this.loop = Player.validModes.has(options.loop) ? options.loop : Player.LOOP_MODES.NONE;
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
this.queue = new Queue();
|
|
43
43
|
this.previousTracks = new Array(50);
|
|
44
44
|
this.previousTracksIndex = 0;
|
|
45
45
|
this.previousTracksCount = 0;
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
this.shouldDeleteMessage = Boolean(options.shouldDeleteMessage);
|
|
48
48
|
this.leaveOnEnd = Boolean(options.leaveOnEnd);
|
|
49
49
|
|
|
@@ -57,43 +57,46 @@ class Player extends EventEmitter {
|
|
|
57
57
|
this.nowPlayingMessage = null;
|
|
58
58
|
this.isAutoplayEnabled = false;
|
|
59
59
|
this.isAutoplay = false;
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
this._boundHandlers = {
|
|
62
62
|
playerUpdate: this._handlePlayerUpdate.bind(this),
|
|
63
63
|
event: this._handleEvent.bind(this)
|
|
64
64
|
};
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
this.on("playerUpdate", this._boundHandlers.playerUpdate);
|
|
67
67
|
this.on("event", this._boundHandlers.event);
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
this._dataStore = null;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
get previous() {
|
|
73
|
-
|
|
73
|
+
if (this.previousTracksCount === 0) return null;
|
|
74
|
+
|
|
75
|
+
const previousIndex = (this.previousTracksIndex - 1 + 50) % 50;
|
|
76
|
+
return this.previousTracks[previousIndex];
|
|
74
77
|
}
|
|
75
|
-
|
|
78
|
+
|
|
76
79
|
get currenttrack() {
|
|
77
80
|
return this.current;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
async autoplay(player) {
|
|
81
84
|
if (!player) throw new Error("Quick Fix: player.autoplay(player)");
|
|
82
|
-
|
|
85
|
+
|
|
83
86
|
if (!this.isAutoplayEnabled) {
|
|
84
87
|
this.aqua.emit("debug", this.guildId, "Autoplay is disabled.");
|
|
85
88
|
return this;
|
|
86
89
|
}
|
|
87
|
-
|
|
90
|
+
|
|
88
91
|
this.isAutoplay = true;
|
|
89
92
|
if (!this.previous) return this;
|
|
90
|
-
|
|
93
|
+
|
|
91
94
|
try {
|
|
92
95
|
const { sourceName, identifier, uri, requester } = this.previous.info;
|
|
93
96
|
this.aqua.emit("debug", this.guildId, `Attempting autoplay for ${sourceName}`);
|
|
94
|
-
|
|
97
|
+
|
|
95
98
|
let query, source, response;
|
|
96
|
-
|
|
99
|
+
|
|
97
100
|
const sourceHandlers = {
|
|
98
101
|
youtube: async () => {
|
|
99
102
|
return {
|
|
@@ -118,51 +121,51 @@ class Player extends EventEmitter {
|
|
|
118
121
|
};
|
|
119
122
|
}
|
|
120
123
|
};
|
|
121
|
-
|
|
124
|
+
|
|
122
125
|
const handler = sourceHandlers[sourceName];
|
|
123
126
|
if (!handler) return this;
|
|
124
|
-
|
|
127
|
+
|
|
125
128
|
const result = await handler();
|
|
126
129
|
if (!result) return this;
|
|
127
|
-
|
|
130
|
+
|
|
128
131
|
({ query, source } = result);
|
|
129
|
-
|
|
132
|
+
|
|
130
133
|
response = await this.aqua.resolve({ query, source, requester });
|
|
131
|
-
|
|
134
|
+
|
|
132
135
|
if (!response?.tracks?.length || ["error", "empty", "LOAD_FAILED", "NO_MATCHES"].includes(response.loadType)) {
|
|
133
136
|
return this.stop();
|
|
134
137
|
}
|
|
135
|
-
|
|
138
|
+
|
|
136
139
|
const track = response.tracks[Math.floor(Math.random() * response.tracks.length)];
|
|
137
|
-
|
|
140
|
+
|
|
138
141
|
if (!track?.info?.title) {
|
|
139
142
|
throw new Error("Invalid track object: missing title or info.");
|
|
140
143
|
}
|
|
141
|
-
|
|
144
|
+
|
|
142
145
|
track.requester = this.previous.requester || { id: "Unknown" };
|
|
143
|
-
|
|
146
|
+
|
|
144
147
|
this.queue.push(track);
|
|
145
148
|
await this.play();
|
|
146
|
-
|
|
149
|
+
|
|
147
150
|
return this;
|
|
148
151
|
} catch (error) {
|
|
149
152
|
console.error("Autoplay error:", error);
|
|
150
153
|
return this.stop();
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
|
-
|
|
156
|
+
|
|
154
157
|
setAutoplay(enabled) {
|
|
155
158
|
this.isAutoplayEnabled = Boolean(enabled);
|
|
156
159
|
this.aqua.emit("debug", this.guildId, `Autoplay has been ${enabled ? "enabled" : "disabled"}.`);
|
|
157
160
|
return this;
|
|
158
161
|
}
|
|
159
|
-
|
|
162
|
+
|
|
160
163
|
addToPreviousTrack(track) {
|
|
161
164
|
if (!track) return;
|
|
162
|
-
|
|
165
|
+
|
|
163
166
|
this.previousTracks[this.previousTracksIndex] = track;
|
|
164
167
|
this.previousTracksIndex = (this.previousTracksIndex + 1) % 50;
|
|
165
|
-
|
|
168
|
+
|
|
166
169
|
if (this.previousTracksCount < 50) {
|
|
167
170
|
this.previousTracksCount++;
|
|
168
171
|
}
|
|
@@ -171,7 +174,7 @@ class Player extends EventEmitter {
|
|
|
171
174
|
_handlePlayerUpdate({ state }) {
|
|
172
175
|
if (state) {
|
|
173
176
|
const { position, timestamp, ping } = state;
|
|
174
|
-
|
|
177
|
+
|
|
175
178
|
if (position !== undefined) this.position = position;
|
|
176
179
|
if (timestamp !== undefined) this.timestamp = timestamp;
|
|
177
180
|
if (ping !== undefined) this.ping = ping;
|
|
@@ -190,7 +193,7 @@ class Player extends EventEmitter {
|
|
|
190
193
|
|
|
191
194
|
async play() {
|
|
192
195
|
if (!this.connected || !this.queue.length) return;
|
|
193
|
-
|
|
196
|
+
|
|
194
197
|
const item = this.queue.shift();
|
|
195
198
|
this.current = item.track ? item : await item.resolve(this.aqua);
|
|
196
199
|
this.playing = true;
|
|
@@ -200,18 +203,19 @@ class Player extends EventEmitter {
|
|
|
200
203
|
return this.updatePlayer({ track: { encoded: this.current.track } });
|
|
201
204
|
}
|
|
202
205
|
|
|
203
|
-
connect(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
connect(options = {}) {
|
|
207
|
+
const { voiceChannel, deaf = true, mute = false } = options;
|
|
208
|
+
|
|
209
|
+
|
|
206
210
|
const payload = {
|
|
207
|
-
guild_id: guildId,
|
|
208
|
-
channel_id: voiceChannel,
|
|
211
|
+
guild_id: this.guildId,
|
|
212
|
+
channel_id: this.voiceChannel,
|
|
209
213
|
self_deaf: deaf,
|
|
210
214
|
self_mute: mute
|
|
211
215
|
};
|
|
212
|
-
|
|
216
|
+
|
|
213
217
|
this.send(payload);
|
|
214
|
-
|
|
218
|
+
|
|
215
219
|
this.connected = true;
|
|
216
220
|
this.aqua.emit("debug", this.guildId, `Player connected to voice channel: ${voiceChannel}.`);
|
|
217
221
|
return this;
|
|
@@ -219,41 +223,41 @@ class Player extends EventEmitter {
|
|
|
219
223
|
|
|
220
224
|
destroy() {
|
|
221
225
|
if (!this.connected) return this;
|
|
222
|
-
|
|
226
|
+
|
|
223
227
|
this.disconnect();
|
|
224
|
-
|
|
228
|
+
|
|
225
229
|
this._cleanupNowPlayingMessage();
|
|
226
|
-
|
|
230
|
+
|
|
227
231
|
this.isAutoplay = false;
|
|
228
232
|
|
|
229
233
|
this.off("playerUpdate", this._boundHandlers.playerUpdate);
|
|
230
234
|
this.off("event", this._boundHandlers.event);
|
|
231
|
-
|
|
235
|
+
|
|
232
236
|
this.aqua.destroyPlayer(this.guildId);
|
|
233
237
|
this.nodes.rest.destroyPlayer(this.guildId);
|
|
234
|
-
|
|
238
|
+
|
|
235
239
|
this.clearData();
|
|
236
240
|
this.removeAllListeners();
|
|
237
|
-
|
|
241
|
+
|
|
238
242
|
this._boundHandlers = null;
|
|
239
243
|
this.queue = null;
|
|
240
244
|
this.previousTracks = null;
|
|
241
245
|
this.connection = null;
|
|
242
246
|
this.filters = null;
|
|
243
|
-
|
|
247
|
+
|
|
244
248
|
return this;
|
|
245
249
|
}
|
|
246
|
-
|
|
250
|
+
|
|
247
251
|
_cleanupNowPlayingMessage() {
|
|
248
252
|
if (this.nowPlayingMessage) {
|
|
249
|
-
this.nowPlayingMessage.delete().catch(() => {});
|
|
253
|
+
this.nowPlayingMessage.delete().catch(() => { });
|
|
250
254
|
this.nowPlayingMessage = null;
|
|
251
255
|
}
|
|
252
256
|
}
|
|
253
257
|
|
|
254
258
|
pause(paused) {
|
|
255
259
|
if (this.paused === paused) return this;
|
|
256
|
-
|
|
260
|
+
|
|
257
261
|
this.paused = paused;
|
|
258
262
|
this.updatePlayer({ paused });
|
|
259
263
|
return this;
|
|
@@ -271,7 +275,7 @@ class Player extends EventEmitter {
|
|
|
271
275
|
|
|
272
276
|
seek(position) {
|
|
273
277
|
if (!this.playing) return this;
|
|
274
|
-
|
|
278
|
+
|
|
275
279
|
this.position += position;
|
|
276
280
|
this.updatePlayer({ position: this.position });
|
|
277
281
|
return this;
|
|
@@ -287,7 +291,7 @@ class Player extends EventEmitter {
|
|
|
287
291
|
|
|
288
292
|
setVolume(volume) {
|
|
289
293
|
if (volume < 0 || volume > 200) throw new Error("Volume must be between 0 and 200.");
|
|
290
|
-
|
|
294
|
+
|
|
291
295
|
this.volume = volume;
|
|
292
296
|
this.updatePlayer({ volume });
|
|
293
297
|
return this;
|
|
@@ -295,7 +299,7 @@ class Player extends EventEmitter {
|
|
|
295
299
|
|
|
296
300
|
setLoop(mode) {
|
|
297
301
|
if (!Player.validModes.has(mode)) throw new Error("Loop mode must be 'none', 'track', or 'queue'.");
|
|
298
|
-
|
|
302
|
+
|
|
299
303
|
this.loop = mode;
|
|
300
304
|
this.updatePlayer({ loop: mode });
|
|
301
305
|
return this;
|
|
@@ -309,26 +313,26 @@ class Player extends EventEmitter {
|
|
|
309
313
|
|
|
310
314
|
setVoiceChannel(channel) {
|
|
311
315
|
if (!channel?.length) throw new TypeError("Channel must be a non-empty string.");
|
|
312
|
-
|
|
316
|
+
|
|
313
317
|
if (this.connected && channel === this.voiceChannel) {
|
|
314
318
|
throw new ReferenceError(`Player already connected to ${channel}.`);
|
|
315
319
|
}
|
|
316
|
-
|
|
320
|
+
|
|
317
321
|
this.voiceChannel = channel;
|
|
318
|
-
|
|
322
|
+
|
|
319
323
|
this.connect({
|
|
320
324
|
deaf: this.deaf,
|
|
321
325
|
guildId: this.guildId,
|
|
322
326
|
voiceChannel: channel,
|
|
323
327
|
mute: this.mute
|
|
324
328
|
});
|
|
325
|
-
|
|
329
|
+
|
|
326
330
|
return this;
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
disconnect() {
|
|
330
334
|
if (!this.connected) return this;
|
|
331
|
-
|
|
335
|
+
|
|
332
336
|
this.connected = false;
|
|
333
337
|
this.send({ guild_id: this.guildId, channel_id: null });
|
|
334
338
|
this.voiceChannel = null;
|
|
@@ -367,7 +371,7 @@ class Player extends EventEmitter {
|
|
|
367
371
|
|
|
368
372
|
async trackEnd(player, track, payload) {
|
|
369
373
|
this.addToPreviousTrack(track);
|
|
370
|
-
|
|
374
|
+
|
|
371
375
|
if (this.shouldDeleteMessage && this.nowPlayingMessage) {
|
|
372
376
|
try {
|
|
373
377
|
await this.nowPlayingMessage.delete();
|
|
@@ -376,7 +380,7 @@ class Player extends EventEmitter {
|
|
|
376
380
|
console.error("Error deleting now playing message:", error);
|
|
377
381
|
}
|
|
378
382
|
}
|
|
379
|
-
|
|
383
|
+
|
|
380
384
|
const reason = payload.reason;
|
|
381
385
|
if (reason === "LOAD_FAILED" || reason === "CLEANUP") {
|
|
382
386
|
if (!player.queue.length) {
|
|
@@ -398,7 +402,7 @@ class Player extends EventEmitter {
|
|
|
398
402
|
await player.play();
|
|
399
403
|
}
|
|
400
404
|
}
|
|
401
|
-
|
|
405
|
+
|
|
402
406
|
async _handleTrackLooping(player, track) {
|
|
403
407
|
if (this.loop === Player.LOOP_MODES.TRACK) {
|
|
404
408
|
player.queue.unshift(track);
|
|
@@ -406,7 +410,7 @@ class Player extends EventEmitter {
|
|
|
406
410
|
player.queue.push(track);
|
|
407
411
|
}
|
|
408
412
|
}
|
|
409
|
-
|
|
413
|
+
|
|
410
414
|
async _handleEmptyQueue(player) {
|
|
411
415
|
if (this.isAutoplayEnabled) {
|
|
412
416
|
await player.autoplay(player);
|
|
@@ -432,7 +436,7 @@ class Player extends EventEmitter {
|
|
|
432
436
|
|
|
433
437
|
async socketClosed(player, payload) {
|
|
434
438
|
const { code, guildId } = payload || {};
|
|
435
|
-
|
|
439
|
+
|
|
436
440
|
if (code === 4015 || code === 4009) {
|
|
437
441
|
this.send({
|
|
438
442
|
guild_id: guildId,
|
|
@@ -441,7 +445,7 @@ class Player extends EventEmitter {
|
|
|
441
445
|
self_deaf: this.deaf,
|
|
442
446
|
});
|
|
443
447
|
}
|
|
444
|
-
|
|
448
|
+
|
|
445
449
|
this.aqua.emit("socketClosed", player, payload);
|
|
446
450
|
this.pause(true);
|
|
447
451
|
this.aqua.emit("debug", this.guildId, "Player paused due to socket closure.");
|