aqualink 1.5.1 → 1.6.0
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/README.md +13 -9
- package/build/handlers/fetchImage.js +3 -4
- package/build/structures/Aqua.js +164 -60
- package/build/structures/Connection.js +13 -18
- package/build/structures/Node.js +184 -123
- package/build/structures/Player.js +125 -91
- package/build/structures/Queue.js +2 -8
- package/build/structures/Rest.js +35 -17
- package/build/structures/Track.js +36 -26
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -18,23 +18,27 @@ This code is based in riffy, but its an 100% Rewrite made from scratch...
|
|
|
18
18
|
- Minimal Requests to the lavalink server (helps the lavalink recourses!)
|
|
19
19
|
- Easy player, node, aqua managing
|
|
20
20
|
- Fast responses from rest and node
|
|
21
|
-
- Playlist support (My mix playlists, youtube playlists)
|
|
21
|
+
- Playlist support (My mix playlists, youtube playlists, spotify playlists)
|
|
22
22
|
|
|
23
23
|
# Docs (Wiki)
|
|
24
24
|
- https://github.com/ToddyTheNoobDud/AquaLink/wiki
|
|
25
25
|
|
|
26
26
|
- Example bot: https://github.com/ToddyTheNoobDud/Thorium-Music
|
|
27
27
|
|
|
28
|
-
#
|
|
28
|
+
# Omg version 1.6.0 woah aqualink
|
|
29
29
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
- Rewrited the `TRACK` handler for better speed by removing redundant checks and code.
|
|
35
|
-
- REMADE the `PLAYER` system to fix bugs, resolve message sending issues, Fixes `EventEmitter` memory leaks (also Fixes `AQUA`), remove unnecessary JSDoc comments, rewrite some methods, and enhance cleanup.
|
|
36
|
-
- 1.5.1 : Fully fixed destroy and the queue handling for delete, also now it deletes from lavalink...
|
|
30
|
+
- Reworked the `TRACK` Manager (This improves the speed by wayyy more, also uses objects, removed useless code)
|
|
31
|
+
- Improved the `REST` Manager (This improves the garbage collector, an faster code, and more optimized)
|
|
32
|
+
- Added enqueue to `QUEUE` (this gets the previous, made for dev), removed addMultiple (useless)
|
|
33
|
+
- Fully Rewrite the `PLAYER` Manager (Way faster resolving, way less recourse intensive, more responsive, better error handling)
|
|
37
34
|
|
|
35
|
+
^^ Now uses the WeakMap and WeakSet for an garbage collector, making it with an better memory management.
|
|
36
|
+
|
|
37
|
+
- Rewrite the `NODE` Manager (reconnect speeds improved, various methods improved, Rewrite the cache and status handler, improve the performance) - Also fixed player resuming.
|
|
38
|
+
- Remade some stuff in `CONNECTION` (this improves error handling, cleaning up, and speed)
|
|
39
|
+
- Rewrite `AQUA` Manager (remade every single method, improved the resolve, made the code dynamic, fixed lots of bugs, uses weakMap too.) - Added autoResume option (true false)
|
|
40
|
+
|
|
41
|
+
- There are way more stuff that i forgot to add on changelog. pls report bugs on my github !
|
|
38
42
|
# How to install
|
|
39
43
|
|
|
40
44
|
`npm install aqualink`
|
|
@@ -22,10 +22,9 @@ async function getImageUrl(info) {
|
|
|
22
22
|
|
|
23
23
|
async function fetchThumbnail(url) {
|
|
24
24
|
try {
|
|
25
|
-
const
|
|
26
|
-
const json = await
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const { body } = await request(url, { method: "GET" });
|
|
26
|
+
const json = await body.json();
|
|
27
|
+
await body.dump();
|
|
29
28
|
return json.thumbnail_url || null;
|
|
30
29
|
} catch (error) {
|
|
31
30
|
console.error(`Error fetching ${url}:`, error);
|
package/build/structures/Aqua.js
CHANGED
|
@@ -3,7 +3,8 @@ const { Node } = require("./Node");
|
|
|
3
3
|
const { Player } = require("./Player");
|
|
4
4
|
const { Track } = require("./Track");
|
|
5
5
|
const { version: pkgVersion } = require("../../package.json");
|
|
6
|
-
|
|
6
|
+
const URL_REGEX = /^https?:\/\//;
|
|
7
|
+
const REQUEST_TIMEOUT = 10000;
|
|
7
8
|
class Aqua extends EventEmitter {
|
|
8
9
|
/**
|
|
9
10
|
* @param {Object} client - The client instance.
|
|
@@ -14,6 +15,7 @@ class Aqua extends EventEmitter {
|
|
|
14
15
|
* @param {string} [options.restVersion="v4"] - Version of the REST API.
|
|
15
16
|
* @param {Array<Object>} [options.plugins=[]] - Plugins to load.
|
|
16
17
|
* @param {string} [options.shouldDeleteMessage='none'] - Should delete your message? (true, false)
|
|
18
|
+
* @param {boolean} [options.autoResume=false] - Automatically resume tracks on reconnect.
|
|
17
19
|
*/
|
|
18
20
|
constructor(client, nodes, options) {
|
|
19
21
|
super();
|
|
@@ -31,138 +33,218 @@ class Aqua extends EventEmitter {
|
|
|
31
33
|
this.version = pkgVersion;
|
|
32
34
|
this.options = options;
|
|
33
35
|
this.send = options.send;
|
|
36
|
+
this.autoResume = options.autoResume || false;
|
|
34
37
|
this.setMaxListeners(0);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
validateInputs(client, nodes, options) {
|
|
38
41
|
if (!client) throw new Error("Client is required to initialize Aqua");
|
|
39
|
-
if (!Array.isArray(nodes) || nodes.length
|
|
42
|
+
if (!Array.isArray(nodes) || !nodes.length) throw new Error(`Nodes must be a non-empty Array (Received ${typeof nodes})`);
|
|
40
43
|
if (typeof options?.send !== "function") throw new Error("Send function is required to initialize Aqua");
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
get leastUsedNodes() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
const activeNodes = [...this.nodeMap.values()].filter(node => node.connected);
|
|
48
|
+
if (!activeNodes.length) return [];
|
|
49
|
+
return activeNodes.sort((a, b) => a.rest.calls - b.rest.calls);
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
init(clientId) {
|
|
50
53
|
if (this.initiated) return this;
|
|
51
54
|
this.clientId = clientId;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
this.nodes.forEach(nodeConfig => this.createNode(nodeConfig));
|
|
58
|
+
this.initiated = true;
|
|
59
|
+
this.plugins.forEach(plugin => plugin.load(this));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
this.initiated = false;
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
return this;
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
createNode(options) {
|
|
69
|
+
const nodeId = options.name || options.host;
|
|
70
|
+
if (this.nodeMap.has(nodeId)) {
|
|
71
|
+
this.destroyNode(nodeId);
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
const node = new Node(this, options, this.options);
|
|
60
|
-
this.nodeMap.set(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
this.nodeMap.set(nodeId, node);
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
node.connect();
|
|
79
|
+
this.emit("nodeCreate", node);
|
|
80
|
+
return node;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.nodeMap.delete(nodeId);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
64
85
|
}
|
|
65
86
|
|
|
66
87
|
destroyNode(identifier) {
|
|
67
88
|
const node = this.nodeMap.get(identifier);
|
|
68
|
-
if (node)
|
|
89
|
+
if (!node) return;
|
|
90
|
+
|
|
91
|
+
try {
|
|
69
92
|
node.disconnect();
|
|
93
|
+
node.removeAllListeners();
|
|
70
94
|
this.nodeMap.delete(identifier);
|
|
71
95
|
this.emit("nodeDestroy", node);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(`Error destroying node ${identifier}:`, error);
|
|
72
98
|
}
|
|
73
99
|
}
|
|
74
100
|
|
|
75
101
|
updateVoiceState(packet) {
|
|
102
|
+
if (!packet?.d?.guild_id) return;
|
|
103
|
+
|
|
76
104
|
const player = this.players.get(packet.d.guild_id);
|
|
77
|
-
if (player
|
|
78
|
-
|
|
105
|
+
if (!player) return;
|
|
106
|
+
|
|
107
|
+
if (packet.t === "VOICE_SERVER_UPDATE" ||
|
|
108
|
+
(packet.t === "VOICE_STATE_UPDATE" && packet.d.user_id === this.clientId)) {
|
|
109
|
+
|
|
110
|
+
const updateType = packet.t === "VOICE_SERVER_UPDATE" ? "setServerUpdate" : "setStateUpdate";
|
|
111
|
+
player.connection[updateType](packet.d);
|
|
112
|
+
|
|
79
113
|
if (packet.d.status === "disconnected") {
|
|
80
|
-
this.cleanupPlayer(player);
|
|
114
|
+
this.cleanupPlayer(player);
|
|
81
115
|
}
|
|
82
116
|
}
|
|
83
117
|
}
|
|
84
118
|
|
|
85
119
|
fetchRegion(region) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
120
|
+
if (!region) return this.leastUsedNodes;
|
|
121
|
+
|
|
122
|
+
const lowerRegion = region.toLowerCase();
|
|
123
|
+
const eligibleNodes = [...this.nodeMap.values()].filter(
|
|
124
|
+
node => node.connected && node.regions?.includes(lowerRegion)
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
return eligibleNodes.sort((a, b) => this.calculateLoad(a) - this.calculateLoad(b));
|
|
90
128
|
}
|
|
91
129
|
|
|
92
130
|
calculateLoad(node) {
|
|
93
|
-
|
|
131
|
+
if (!node?.stats?.cpu) return 0;
|
|
132
|
+
const { systemLoad, cores } = node.stats.cpu;
|
|
133
|
+
return (systemLoad / cores) * 100;
|
|
94
134
|
}
|
|
95
135
|
|
|
96
136
|
createConnection(options) {
|
|
97
137
|
this.ensureInitialized();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
|
|
139
|
+
const existingPlayer = this.players.get(options.guildId);
|
|
140
|
+
if (existingPlayer?.voiceChannel) return existingPlayer;
|
|
141
|
+
|
|
142
|
+
const node = options.region ?
|
|
143
|
+
this.fetchRegion(options.region)[0] :
|
|
144
|
+
this.leastUsedNodes[0];
|
|
145
|
+
|
|
101
146
|
if (!node) throw new Error("No nodes are available");
|
|
102
147
|
return this.createPlayer(node, options);
|
|
103
148
|
}
|
|
104
149
|
|
|
105
150
|
createPlayer(node, options) {
|
|
151
|
+
this.destroyPlayer(options.guildId);
|
|
152
|
+
|
|
106
153
|
const player = new Player(this, node, options);
|
|
107
154
|
this.players.set(options.guildId, player);
|
|
108
|
-
player
|
|
155
|
+
const weakPlayer = new WeakRef(player);
|
|
156
|
+
|
|
157
|
+
const destroyHandler = () => {
|
|
158
|
+
const playerInstance = weakPlayer.deref();
|
|
159
|
+
if (playerInstance) {
|
|
160
|
+
this.cleanupPlayer(playerInstance);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
player.once("destroy", destroyHandler);
|
|
109
165
|
player.connect(options);
|
|
110
|
-
player.on("destroy", () => this.cleanupPlayer(player)); // Listen for player destruction
|
|
111
166
|
this.emit("playerCreate", player);
|
|
167
|
+
|
|
112
168
|
return player;
|
|
113
169
|
}
|
|
114
170
|
|
|
115
171
|
destroyPlayer(guildId) {
|
|
116
172
|
const player = this.players.get(guildId);
|
|
117
|
-
if (player)
|
|
173
|
+
if (!player) return;
|
|
174
|
+
|
|
175
|
+
try {
|
|
118
176
|
player.clearData();
|
|
177
|
+
player.removeAllListeners(); // Clear all event listeners
|
|
119
178
|
player.destroy();
|
|
120
179
|
this.players.delete(guildId);
|
|
121
180
|
this.emit("playerDestroy", player);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error(`Error destroying player for guild ${guildId}:`, error);
|
|
122
183
|
}
|
|
123
184
|
}
|
|
124
|
-
|
|
125
185
|
async resolve({ query, source = this.defaultSearchPlatform, requester, nodes }) {
|
|
126
186
|
this.ensureInitialized();
|
|
127
187
|
const requestNode = this.getRequestNode(nodes);
|
|
128
188
|
const formattedQuery = this.formatQuery(query, source);
|
|
189
|
+
|
|
129
190
|
try {
|
|
130
|
-
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
193
|
+
|
|
194
|
+
const response = await requestNode.rest.makeRequest("GET",
|
|
195
|
+
`/v4/loadtracks?identifier=${encodeURIComponent(formattedQuery)}`,
|
|
196
|
+
{ signal: controller.signal }
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
clearTimeout(timeoutId);
|
|
200
|
+
|
|
131
201
|
if (["empty", "NO_MATCHES"].includes(response.loadType)) {
|
|
132
|
-
|
|
202
|
+
return await this.handleNoMatches(requestNode.rest, query);
|
|
133
203
|
}
|
|
134
204
|
return this.constructorResponse(response, requester, requestNode);
|
|
135
205
|
} catch (error) {
|
|
136
|
-
|
|
137
|
-
|
|
206
|
+
if (error.name === 'AbortError') {
|
|
207
|
+
throw new Error("Request timed out");
|
|
208
|
+
}
|
|
209
|
+
throw new Error(`Failed to resolve track: ${error.message}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getRequestNode(nodes) {
|
|
214
|
+
if (nodes && !(typeof nodes === "string" || nodes instanceof Node)) {
|
|
215
|
+
throw new TypeError(`'nodes' must be a string or Node instance, received: ${typeof nodes}`);
|
|
138
216
|
}
|
|
217
|
+
return (typeof nodes === 'string' ? this.nodeMap.get(nodes) : nodes) ?? this.leastUsedNodes[0];
|
|
139
218
|
}
|
|
140
219
|
|
|
141
220
|
ensureInitialized() {
|
|
142
221
|
if (!this.initiated) throw new Error("Aqua must be initialized before this operation");
|
|
143
222
|
}
|
|
144
223
|
|
|
145
|
-
getRequestNode(nodes) {
|
|
146
|
-
if (nodes && (typeof nodes !== "string" && !(nodes instanceof Node))) {
|
|
147
|
-
throw new Error(`'nodes' must be a string or Node instance, but received: ${typeof nodes}`);
|
|
148
|
-
}
|
|
149
|
-
return (typeof nodes === 'string' ? this.nodeMap.get(nodes) : nodes) || this.leastUsedNodes[0];
|
|
150
|
-
}
|
|
151
224
|
|
|
152
225
|
formatQuery(query, source) {
|
|
153
|
-
return
|
|
226
|
+
return URL_REGEX.test(query) ? query : `${source}:${query}`;
|
|
154
227
|
}
|
|
155
228
|
|
|
156
229
|
async handleNoMatches(rest, query) {
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
232
|
+
|
|
157
233
|
try {
|
|
158
|
-
const youtubeResponse = await rest.makeRequest("GET",
|
|
234
|
+
const youtubeResponse = await rest.makeRequest("GET",
|
|
235
|
+
`/v4/loadtracks?identifier=https://www.youtube.com/watch?v=${query}`,
|
|
236
|
+
{ signal: controller.signal }
|
|
237
|
+
);
|
|
238
|
+
|
|
159
239
|
if (["empty", "NO_MATCHES"].includes(youtubeResponse.loadType)) {
|
|
160
|
-
return await rest.makeRequest("GET",
|
|
240
|
+
return await rest.makeRequest("GET",
|
|
241
|
+
`/v4/loadtracks?identifier=https://open.spotify.com/track/${query}`,
|
|
242
|
+
{ signal: controller.signal }
|
|
243
|
+
);
|
|
161
244
|
}
|
|
162
245
|
return youtubeResponse;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
throw new Error("Failed to handle no matches");
|
|
246
|
+
} finally {
|
|
247
|
+
clearTimeout(timeoutId);
|
|
166
248
|
}
|
|
167
249
|
}
|
|
168
250
|
|
|
@@ -171,29 +253,34 @@ class Aqua extends EventEmitter {
|
|
|
171
253
|
loadType: response.loadType,
|
|
172
254
|
exception: null,
|
|
173
255
|
playlistInfo: null,
|
|
174
|
-
pluginInfo: response.pluginInfo
|
|
256
|
+
pluginInfo: response.pluginInfo ?? {},
|
|
175
257
|
tracks: [],
|
|
176
258
|
};
|
|
177
|
-
|
|
178
|
-
if (loadType === "error" || loadType === "LOAD_FAILED") {
|
|
179
|
-
baseResponse.exception = data
|
|
259
|
+
|
|
260
|
+
if (response.loadType === "error" || response.loadType === "LOAD_FAILED") {
|
|
261
|
+
baseResponse.exception = response.data ?? response.exception;
|
|
180
262
|
return baseResponse;
|
|
181
263
|
}
|
|
182
|
-
|
|
264
|
+
|
|
265
|
+
const trackFactory = (trackData) => new Track(trackData, requester, requestNode);
|
|
266
|
+
|
|
267
|
+
switch (response.loadType) {
|
|
183
268
|
case "track":
|
|
184
|
-
if (data) {
|
|
185
|
-
baseResponse.tracks.push(
|
|
269
|
+
if (response.data) {
|
|
270
|
+
baseResponse.tracks.push(trackFactory(response.data));
|
|
186
271
|
}
|
|
187
272
|
break;
|
|
188
273
|
case "playlist":
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
274
|
+
if (response.data?.info) {
|
|
275
|
+
baseResponse.playlistInfo = {
|
|
276
|
+
name: response.data.info.name ?? response.data.info.title,
|
|
277
|
+
...response.data.info,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
baseResponse.tracks = (response.data?.tracks ?? []).map(trackFactory);
|
|
194
281
|
break;
|
|
195
282
|
case "search":
|
|
196
|
-
baseResponse.tracks = (data
|
|
283
|
+
baseResponse.tracks = (response.data ?? []).map(trackFactory);
|
|
197
284
|
break;
|
|
198
285
|
}
|
|
199
286
|
return baseResponse;
|
|
@@ -206,38 +293,55 @@ class Aqua extends EventEmitter {
|
|
|
206
293
|
}
|
|
207
294
|
|
|
208
295
|
cleanupIdle() {
|
|
296
|
+
const now = Date.now();
|
|
209
297
|
for (const [guildId, player] of this.players) {
|
|
210
|
-
if (!player.playing && !player.paused && player.queue.isEmpty()
|
|
298
|
+
if (!player.playing && !player.paused && player.queue.isEmpty() &&
|
|
299
|
+
(now - player.lastActivity) > this.options.idleTimeout) {
|
|
211
300
|
this.cleanupPlayer(player);
|
|
212
301
|
}
|
|
213
302
|
}
|
|
214
303
|
}
|
|
215
304
|
|
|
216
305
|
cleanupPlayer(player) {
|
|
217
|
-
if (player)
|
|
306
|
+
if (!player) return;
|
|
307
|
+
|
|
308
|
+
try {
|
|
218
309
|
player.clearData();
|
|
310
|
+
player.removeAllListeners();
|
|
219
311
|
player.destroy();
|
|
220
312
|
this.players.delete(player.guildId);
|
|
221
313
|
this.emit("playerDestroy", player);
|
|
314
|
+
} catch (error) {
|
|
315
|
+
console.error(`Error during player cleanup: ${error.message}`);
|
|
222
316
|
}
|
|
223
317
|
}
|
|
224
318
|
|
|
225
319
|
cleanup() {
|
|
320
|
+
// Clear all players
|
|
226
321
|
for (const player of this.players.values()) {
|
|
227
322
|
this.cleanupPlayer(player);
|
|
228
323
|
}
|
|
324
|
+
|
|
325
|
+
// Clear all nodes
|
|
229
326
|
for (const node of this.nodeMap.values()) {
|
|
230
327
|
this.destroyNode(node.name || node.host);
|
|
231
328
|
}
|
|
329
|
+
|
|
330
|
+
// Clear maps
|
|
232
331
|
this.nodeMap.clear();
|
|
233
332
|
this.players.clear();
|
|
333
|
+
|
|
334
|
+
// Clear references
|
|
234
335
|
this.client = null;
|
|
235
336
|
this.nodes = null;
|
|
337
|
+
this.plugins?.forEach(plugin => plugin.unload?.(this));
|
|
236
338
|
this.plugins = null;
|
|
237
339
|
this.options = null;
|
|
238
340
|
this.send = null;
|
|
239
341
|
this.version = null;
|
|
342
|
+
|
|
343
|
+
// Remove all listeners
|
|
344
|
+
this.removeAllListeners();
|
|
240
345
|
}
|
|
241
346
|
}
|
|
242
|
-
|
|
243
347
|
module.exports = { Aqua };
|
|
@@ -8,24 +8,11 @@ class Connection {
|
|
|
8
8
|
this.voiceChannel = player.voiceChannel;
|
|
9
9
|
this.lastUpdateTime = 0;
|
|
10
10
|
this.updateThrottle = 1000;
|
|
11
|
-
|
|
12
|
-
// Bind event listeners
|
|
13
|
-
this.onPlayerMove = this.onPlayerMove.bind(this);
|
|
14
|
-
this.onPlayerLeave = this.onPlayerLeave.bind(this);
|
|
15
|
-
this.player.aqua.on("playerMove", this.onPlayerMove);
|
|
16
|
-
this.player.aqua.on("playerLeave", this.onPlayerLeave);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
onPlayerMove(oldChannel, newChannel) {
|
|
20
|
-
// Handle player movement
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
onPlayerLeave(channelId) {
|
|
24
|
-
// Handle player leaving
|
|
25
11
|
}
|
|
26
12
|
|
|
27
13
|
setServerUpdate({ endpoint, token }) {
|
|
28
14
|
if (!endpoint) throw new Error("Missing 'endpoint' property in VOICE_SERVER_UPDATE");
|
|
15
|
+
|
|
29
16
|
const newRegion = endpoint.split('.')[0].replace(/[0-9]/g, "");
|
|
30
17
|
if (this.region !== newRegion) {
|
|
31
18
|
this.updateRegion(newRegion, endpoint, token);
|
|
@@ -38,7 +25,9 @@ class Connection {
|
|
|
38
25
|
this.region = newRegion;
|
|
39
26
|
this.voice.endpoint = endpoint;
|
|
40
27
|
this.voice.token = token;
|
|
28
|
+
|
|
41
29
|
this.player.aqua.emit("debug", `[Player ${this.player.guildId} - CONNECTION] ${previousVoiceRegion ? `Changed Voice Region from ${previousVoiceRegion} to ${this.region}` : `Voice Server: ${this.region}`}`);
|
|
30
|
+
|
|
42
31
|
if (this.player.paused) {
|
|
43
32
|
this.player.pause(false);
|
|
44
33
|
}
|
|
@@ -49,11 +38,13 @@ class Connection {
|
|
|
49
38
|
this.cleanup();
|
|
50
39
|
return;
|
|
51
40
|
}
|
|
41
|
+
|
|
52
42
|
if (this.player.voiceChannel !== data.channel_id) {
|
|
53
43
|
this.player.aqua.emit("playerMove", this.player.voiceChannel, data.channel_id);
|
|
54
44
|
this.player.voiceChannel = data.channel_id;
|
|
55
45
|
this.voiceChannel = data.channel_id;
|
|
56
46
|
}
|
|
47
|
+
|
|
57
48
|
this.selfDeaf = data.self_deaf;
|
|
58
49
|
this.selfMute = data.self_mute;
|
|
59
50
|
this.voice.sessionId = data.session_id;
|
|
@@ -63,25 +54,29 @@ class Connection {
|
|
|
63
54
|
const currentTime = Date.now();
|
|
64
55
|
if (currentTime - this.lastUpdateTime >= this.updateThrottle) {
|
|
65
56
|
this.lastUpdateTime = currentTime;
|
|
66
|
-
|
|
57
|
+
|
|
58
|
+
const data = {
|
|
67
59
|
voice: this.voice,
|
|
68
60
|
volume: this.player.volume,
|
|
69
|
-
}
|
|
61
|
+
};
|
|
62
|
+
|
|
70
63
|
this.player.nodes.rest.updatePlayer({
|
|
71
64
|
guildId: this.player.guildId,
|
|
72
65
|
data,
|
|
66
|
+
}).catch(err => {
|
|
67
|
+
this.player.aqua.emit("apiError", "updatePlayer", err);
|
|
73
68
|
});
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
cleanup() {
|
|
78
|
-
this.player.aqua.off("playerMove", this.onPlayerMove);
|
|
79
|
-
this.player.aqua.off("playerLeave", this.onPlayerLeave);
|
|
80
73
|
this.player.aqua.emit("playerLeave", this.player.voiceChannel);
|
|
81
74
|
this.player.voiceChannel = null;
|
|
82
75
|
this.voiceChannel = null;
|
|
76
|
+
|
|
83
77
|
this.player.destroy();
|
|
84
78
|
this.player.aqua.emit("playerDestroy", this.player);
|
|
79
|
+
|
|
85
80
|
this.player = null;
|
|
86
81
|
this.voice = null;
|
|
87
82
|
this.region = null;
|