aqualink 2.1.3 → 2.3.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 +31 -35
- package/build/handlers/autoplay.js +45 -15
- package/build/handlers/fetchImage.js +23 -30
- package/build/index.d.ts +255 -1211
- package/build/structures/Aqua.js +68 -70
- package/build/structures/Filters.js +127 -87
- package/build/structures/Node.js +207 -171
- package/build/structures/Player.js +122 -87
- package/build/structures/Rest.js +40 -44
- package/package.json +1 -1
|
@@ -26,6 +26,7 @@ class Player extends EventEmitter {
|
|
|
26
26
|
|
|
27
27
|
constructor(aqua, nodes, options = {}) {
|
|
28
28
|
super();
|
|
29
|
+
|
|
29
30
|
this.aqua = aqua;
|
|
30
31
|
this.nodes = nodes;
|
|
31
32
|
this.guildId = options.guildId;
|
|
@@ -35,47 +36,41 @@ class Player extends EventEmitter {
|
|
|
35
36
|
this.connection = new Connection(this);
|
|
36
37
|
this.filters = new Filters(this);
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
this.volume = defaultVolume > 200 ? 200 : (defaultVolume < 0 ? 0 : defaultVolume);
|
|
40
|
-
|
|
39
|
+
this.volume = Math.max(0, Math.min(options.defaultVolume ?? 100, 200));
|
|
41
40
|
this.loop = Player.validModes.has(options.loop) ? options.loop : Player.LOOP_MODES.NONE;
|
|
42
41
|
|
|
43
42
|
this.queue = new Queue();
|
|
44
|
-
this.previousTracks =
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
43
|
+
this.previousTracks = new Array(50);
|
|
44
|
+
this.previousTracksIndex = 0;
|
|
45
|
+
this.previousTracksCount = 0;
|
|
46
|
+
|
|
47
|
+
this.shouldDeleteMessage = Boolean(options.shouldDeleteMessage);
|
|
48
|
+
this.leaveOnEnd = Boolean(options.leaveOnEnd);
|
|
47
49
|
|
|
48
50
|
this.playing = false;
|
|
49
51
|
this.paused = false;
|
|
50
52
|
this.connected = false;
|
|
51
53
|
this.current = null;
|
|
54
|
+
this.position = 0;
|
|
52
55
|
this.timestamp = 0;
|
|
53
56
|
this.ping = 0;
|
|
54
57
|
this.nowPlayingMessage = null;
|
|
55
|
-
|
|
58
|
+
this.isAutoplayEnabled = false;
|
|
56
59
|
this.isAutoplay = false;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
this.previousTracks.unshift(track);
|
|
63
|
-
},
|
|
64
|
-
_cleanup: () => {
|
|
65
|
-
this.previousTracks = [];
|
|
66
|
-
this.isAutoplay = false;
|
|
67
|
-
}
|
|
60
|
+
|
|
61
|
+
this._boundHandlers = {
|
|
62
|
+
playerUpdate: this._handlePlayerUpdate.bind(this),
|
|
63
|
+
event: this._handleEvent.bind(this)
|
|
68
64
|
};
|
|
69
|
-
|
|
70
|
-
this._handlePlayerUpdate = this._handlePlayerUpdate.bind(this);
|
|
71
|
-
this._handleEvent = this._handleEvent.bind(this);
|
|
72
65
|
|
|
73
|
-
this.on("playerUpdate", this.
|
|
74
|
-
this.on("event", this.
|
|
66
|
+
this.on("playerUpdate", this._boundHandlers.playerUpdate);
|
|
67
|
+
this.on("event", this._boundHandlers.event);
|
|
68
|
+
|
|
69
|
+
this._dataStore = null;
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
get previous() {
|
|
78
|
-
return this.previousTracks[
|
|
73
|
+
return this.previousTracksCount > 0 ? this.previousTracks[this.previousTracksIndex] : null;
|
|
79
74
|
}
|
|
80
75
|
|
|
81
76
|
get currenttrack() {
|
|
@@ -99,26 +94,38 @@ class Player extends EventEmitter {
|
|
|
99
94
|
|
|
100
95
|
let query, source, response;
|
|
101
96
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
const sourceHandlers = {
|
|
98
|
+
youtube: async () => {
|
|
99
|
+
return {
|
|
100
|
+
query: `https://www.youtube.com/watch?v=${identifier}&list=RD${identifier}`,
|
|
101
|
+
source: "ytmsearch"
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
soundcloud: async () => {
|
|
108
105
|
const scResults = await scAutoPlay(uri);
|
|
109
|
-
if (!scResults?.length) return
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
if (!scResults?.length) return null;
|
|
107
|
+
return {
|
|
108
|
+
query: scResults[0],
|
|
109
|
+
source: "scsearch"
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
spotify: async () => {
|
|
114
113
|
const spResult = await spAutoPlay(identifier);
|
|
115
|
-
if (!spResult) return
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
114
|
+
if (!spResult) return null;
|
|
115
|
+
return {
|
|
116
|
+
query: `https://open.spotify.com/track/${spResult}`,
|
|
117
|
+
source: "spotify"
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const handler = sourceHandlers[sourceName];
|
|
123
|
+
if (!handler) return this;
|
|
124
|
+
|
|
125
|
+
const result = await handler();
|
|
126
|
+
if (!result) return this;
|
|
127
|
+
|
|
128
|
+
({ query, source } = result);
|
|
122
129
|
|
|
123
130
|
response = await this.aqua.resolve({ query, source, requester });
|
|
124
131
|
|
|
@@ -147,24 +154,27 @@ class Player extends EventEmitter {
|
|
|
147
154
|
setAutoplay(enabled) {
|
|
148
155
|
this.isAutoplayEnabled = Boolean(enabled);
|
|
149
156
|
this.aqua.emit("debug", this.guildId, `Autoplay has been ${enabled ? "enabled" : "disabled"}.`);
|
|
157
|
+
return this;
|
|
150
158
|
}
|
|
151
159
|
|
|
152
|
-
|
|
153
|
-
|
|
154
160
|
addToPreviousTrack(track) {
|
|
155
161
|
if (!track) return;
|
|
156
162
|
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
this.previousTracks[this.previousTracksIndex] = track;
|
|
164
|
+
this.previousTracksIndex = (this.previousTracksIndex + 1) % 50;
|
|
165
|
+
|
|
166
|
+
if (this.previousTracksCount < 50) {
|
|
167
|
+
this.previousTracksCount++;
|
|
159
168
|
}
|
|
160
|
-
this.previousTracks.unshift(track);
|
|
161
169
|
}
|
|
162
170
|
|
|
163
171
|
_handlePlayerUpdate({ state }) {
|
|
164
172
|
if (state) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (
|
|
173
|
+
const { position, timestamp, ping } = state;
|
|
174
|
+
|
|
175
|
+
if (position !== undefined) this.position = position;
|
|
176
|
+
if (timestamp !== undefined) this.timestamp = timestamp;
|
|
177
|
+
if (ping !== undefined) this.ping = ping;
|
|
168
178
|
}
|
|
169
179
|
this.aqua.emit("playerUpdate", this, { state });
|
|
170
180
|
}
|
|
@@ -193,12 +203,14 @@ class Player extends EventEmitter {
|
|
|
193
203
|
connect({ guildId, voiceChannel, deaf = true, mute = false }) {
|
|
194
204
|
if (this.connected) throw new Error("Player is already connected.");
|
|
195
205
|
|
|
196
|
-
|
|
206
|
+
const payload = {
|
|
197
207
|
guild_id: guildId,
|
|
198
208
|
channel_id: voiceChannel,
|
|
199
209
|
self_deaf: deaf,
|
|
200
210
|
self_mute: mute
|
|
201
|
-
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
this.send(payload);
|
|
202
214
|
|
|
203
215
|
this.connected = true;
|
|
204
216
|
this.aqua.emit("debug", this.guildId, `Player connected to voice channel: ${voiceChannel}.`);
|
|
@@ -210,18 +222,34 @@ class Player extends EventEmitter {
|
|
|
210
222
|
|
|
211
223
|
this.disconnect();
|
|
212
224
|
|
|
213
|
-
this.
|
|
225
|
+
this._cleanupNowPlayingMessage();
|
|
214
226
|
|
|
215
|
-
|
|
216
|
-
this._autoplay._cleanup();
|
|
217
|
-
}
|
|
227
|
+
this.isAutoplay = false;
|
|
218
228
|
|
|
229
|
+
this.off("playerUpdate", this._boundHandlers.playerUpdate);
|
|
230
|
+
this.off("event", this._boundHandlers.event);
|
|
231
|
+
|
|
219
232
|
this.aqua.destroyPlayer(this.guildId);
|
|
220
233
|
this.nodes.rest.destroyPlayer(this.guildId);
|
|
234
|
+
|
|
221
235
|
this.clearData();
|
|
222
236
|
this.removeAllListeners();
|
|
237
|
+
|
|
238
|
+
this._boundHandlers = null;
|
|
239
|
+
this.queue = null;
|
|
240
|
+
this.previousTracks = null;
|
|
241
|
+
this.connection = null;
|
|
242
|
+
this.filters = null;
|
|
243
|
+
|
|
223
244
|
return this;
|
|
224
245
|
}
|
|
246
|
+
|
|
247
|
+
_cleanupNowPlayingMessage() {
|
|
248
|
+
if (this.nowPlayingMessage) {
|
|
249
|
+
this.nowPlayingMessage.delete().catch(() => {});
|
|
250
|
+
this.nowPlayingMessage = null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
225
253
|
|
|
226
254
|
pause(paused) {
|
|
227
255
|
if (this.paused === paused) return this;
|
|
@@ -287,6 +315,7 @@ class Player extends EventEmitter {
|
|
|
287
315
|
}
|
|
288
316
|
|
|
289
317
|
this.voiceChannel = channel;
|
|
318
|
+
|
|
290
319
|
this.connect({
|
|
291
320
|
deaf: this.deaf,
|
|
292
321
|
guildId: this.guildId,
|
|
@@ -298,6 +327,8 @@ class Player extends EventEmitter {
|
|
|
298
327
|
}
|
|
299
328
|
|
|
300
329
|
disconnect() {
|
|
330
|
+
if (!this.connected) return this;
|
|
331
|
+
|
|
301
332
|
this.connected = false;
|
|
302
333
|
this.send({ guild_id: this.guildId, channel_id: null });
|
|
303
334
|
this.voiceChannel = null;
|
|
@@ -329,17 +360,14 @@ class Player extends EventEmitter {
|
|
|
329
360
|
}
|
|
330
361
|
|
|
331
362
|
async trackStart(player, track) {
|
|
332
|
-
this.
|
|
363
|
+
this.playing = true;
|
|
364
|
+
this.paused = false;
|
|
333
365
|
this.aqua.emit("trackStart", player, track);
|
|
334
366
|
}
|
|
335
367
|
|
|
336
|
-
async trackChange(player, track) {
|
|
337
|
-
this.updateTrackState(true, false);
|
|
338
|
-
this.aqua.emit("trackChange", player, track);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
368
|
async trackEnd(player, track, payload) {
|
|
342
369
|
this.addToPreviousTrack(track);
|
|
370
|
+
|
|
343
371
|
if (this.shouldDeleteMessage && this.nowPlayingMessage) {
|
|
344
372
|
try {
|
|
345
373
|
await this.nowPlayingMessage.delete();
|
|
@@ -348,37 +376,47 @@ class Player extends EventEmitter {
|
|
|
348
376
|
console.error("Error deleting now playing message:", error);
|
|
349
377
|
}
|
|
350
378
|
}
|
|
351
|
-
|
|
352
|
-
|
|
379
|
+
|
|
380
|
+
const reason = payload.reason;
|
|
381
|
+
if (reason === "LOAD_FAILED" || reason === "CLEANUP") {
|
|
353
382
|
if (!player.queue.length) {
|
|
354
383
|
this.clearData();
|
|
355
384
|
this.aqua.emit("queueEnd", player);
|
|
356
385
|
} else {
|
|
386
|
+
this.aqua.emit("trackEnd", player, track, reason);
|
|
357
387
|
await player.play();
|
|
358
388
|
}
|
|
359
389
|
return;
|
|
360
390
|
}
|
|
361
391
|
|
|
392
|
+
await this._handleTrackLooping(player, track);
|
|
393
|
+
|
|
394
|
+
if (player.queue.isEmpty()) {
|
|
395
|
+
await this._handleEmptyQueue(player);
|
|
396
|
+
} else {
|
|
397
|
+
this.aqua.emit("trackEnd", player, track, reason);
|
|
398
|
+
await player.play();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async _handleTrackLooping(player, track) {
|
|
362
403
|
if (this.loop === Player.LOOP_MODES.TRACK) {
|
|
363
404
|
player.queue.unshift(track);
|
|
364
405
|
} else if (this.loop === Player.LOOP_MODES.QUEUE) {
|
|
365
406
|
player.queue.push(track);
|
|
366
407
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
this.playing = false;
|
|
373
|
-
if (this.leaveOnEnd) {
|
|
374
|
-
this.clearData();
|
|
375
|
-
this.cleanup();
|
|
376
|
-
}
|
|
377
|
-
this.aqua.emit("queueEnd", player);
|
|
378
|
-
}
|
|
379
|
-
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async _handleEmptyQueue(player) {
|
|
411
|
+
if (this.isAutoplayEnabled) {
|
|
412
|
+
await player.autoplay(player);
|
|
380
413
|
} else {
|
|
381
|
-
|
|
414
|
+
this.playing = false;
|
|
415
|
+
if (this.leaveOnEnd) {
|
|
416
|
+
this.clearData();
|
|
417
|
+
this.cleanup();
|
|
418
|
+
}
|
|
419
|
+
this.aqua.emit("queueEnd", player);
|
|
382
420
|
}
|
|
383
421
|
}
|
|
384
422
|
|
|
@@ -393,11 +431,11 @@ class Player extends EventEmitter {
|
|
|
393
431
|
}
|
|
394
432
|
|
|
395
433
|
async socketClosed(player, payload) {
|
|
396
|
-
const code = payload
|
|
434
|
+
const { code, guildId } = payload || {};
|
|
397
435
|
|
|
398
436
|
if (code === 4015 || code === 4009) {
|
|
399
437
|
this.send({
|
|
400
|
-
guild_id:
|
|
438
|
+
guild_id: guildId,
|
|
401
439
|
channel_id: this.voiceChannel,
|
|
402
440
|
self_mute: this.mute,
|
|
403
441
|
self_deaf: this.deaf,
|
|
@@ -415,7 +453,7 @@ class Player extends EventEmitter {
|
|
|
415
453
|
|
|
416
454
|
set(key, value) {
|
|
417
455
|
if (!this._dataStore) {
|
|
418
|
-
this._dataStore = new
|
|
456
|
+
this._dataStore = new Map();
|
|
419
457
|
}
|
|
420
458
|
this._dataStore.set(key, value);
|
|
421
459
|
}
|
|
@@ -425,7 +463,9 @@ class Player extends EventEmitter {
|
|
|
425
463
|
}
|
|
426
464
|
|
|
427
465
|
clearData() {
|
|
428
|
-
if (this.previousTracks)
|
|
466
|
+
if (this.previousTracks) {
|
|
467
|
+
this.previousTracksCount = 0;
|
|
468
|
+
}
|
|
429
469
|
this._dataStore = null;
|
|
430
470
|
return this;
|
|
431
471
|
}
|
|
@@ -444,11 +484,6 @@ class Player extends EventEmitter {
|
|
|
444
484
|
this.destroy();
|
|
445
485
|
}
|
|
446
486
|
}
|
|
447
|
-
|
|
448
|
-
updateTrackState(playing, paused) {
|
|
449
|
-
this.playing = playing;
|
|
450
|
-
this.paused = paused;
|
|
451
|
-
}
|
|
452
487
|
}
|
|
453
488
|
|
|
454
489
|
module.exports = Player;
|
package/build/structures/Rest.js
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
const https = require("https");
|
|
3
3
|
const http = require("http");
|
|
4
4
|
|
|
5
|
-
let http2
|
|
5
|
+
let http2;
|
|
6
|
+
try {
|
|
7
|
+
http2 = require("http2");
|
|
8
|
+
} catch (e) {
|
|
9
|
+
}
|
|
6
10
|
|
|
7
11
|
class Rest {
|
|
8
|
-
constructor(aqua, { secure, host, port, sessionId, password }) {
|
|
12
|
+
constructor(aqua, { secure, host, port, sessionId, password, timeout = 30000 }) {
|
|
9
13
|
this.aqua = aqua;
|
|
10
14
|
this.sessionId = sessionId;
|
|
11
15
|
this.version = "v4";
|
|
@@ -14,29 +18,17 @@ class Rest {
|
|
|
14
18
|
"Content-Type": "application/json",
|
|
15
19
|
"Authorization": password,
|
|
16
20
|
};
|
|
17
|
-
|
|
18
21
|
this.secure = secure;
|
|
22
|
+
this.timeout = timeout;
|
|
23
|
+
|
|
24
|
+
this.client = this.initializeClient();
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
if (this.client) return this.client;
|
|
23
|
-
|
|
27
|
+
initializeClient() {
|
|
24
28
|
if (this.secure) {
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
http2 = require("http2");
|
|
28
|
-
this.client = http2;
|
|
29
|
-
} catch (e) {
|
|
30
|
-
this.client = https;
|
|
31
|
-
}
|
|
32
|
-
} else {
|
|
33
|
-
this.client = http2;
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
this.client = http;
|
|
29
|
+
return http2 || https;
|
|
37
30
|
}
|
|
38
|
-
|
|
39
|
-
return this.client;
|
|
31
|
+
return http;
|
|
40
32
|
}
|
|
41
33
|
|
|
42
34
|
setSessionId(sessionId) {
|
|
@@ -50,22 +42,24 @@ class Rest {
|
|
|
50
42
|
};
|
|
51
43
|
|
|
52
44
|
return new Promise((resolve, reject) => {
|
|
53
|
-
const client = this.getClient();
|
|
54
45
|
const url = `${this.baseUrl}${endpoint}`;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
46
|
+
const req = this.client.request(url, options, (res) => {
|
|
47
|
+
res.setEncoding('utf8');
|
|
48
|
+
|
|
49
|
+
let data = '';
|
|
50
|
+
|
|
51
|
+
res.on("data", (chunk) => {
|
|
52
|
+
data += chunk;
|
|
53
|
+
});
|
|
58
54
|
|
|
59
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
60
55
|
res.on("end", () => {
|
|
61
56
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
62
|
-
if (
|
|
57
|
+
if (!data) {
|
|
63
58
|
resolve(null);
|
|
64
59
|
return;
|
|
65
60
|
}
|
|
66
61
|
|
|
67
62
|
try {
|
|
68
|
-
const data = Buffer.concat(chunks).toString('utf8');
|
|
69
63
|
resolve(data ? JSON.parse(data) : null);
|
|
70
64
|
} catch (error) {
|
|
71
65
|
reject(new Error(`Failed to parse response: ${error.message}`));
|
|
@@ -141,25 +135,27 @@ class Rest {
|
|
|
141
135
|
}
|
|
142
136
|
|
|
143
137
|
async getLyrics({ track }) {
|
|
144
|
-
if (!track)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
138
|
+
if (!track) return null;
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
if (track.search) {
|
|
142
|
+
const query = track.info.title;
|
|
143
|
+
try {
|
|
144
|
+
const res = await this.makeRequest("GET", `/${this.version}/lyrics/search?query=${query}&source=genius`);
|
|
145
|
+
if (res) return res;
|
|
146
|
+
} catch (err) {}
|
|
147
|
+
} else {
|
|
148
|
+
this.validateSessionId();
|
|
149
|
+
return await this.makeRequest(
|
|
150
|
+
"GET",
|
|
151
|
+
`/${this.version}/sessions/${this.sessionId}/players/${track.guild_id}/track/lyrics?skipTrackSource=false`
|
|
152
|
+
);
|
|
155
153
|
}
|
|
154
|
+
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error("Failed to fetch lyrics:", error.message);
|
|
157
|
+
return null;
|
|
156
158
|
}
|
|
157
|
-
|
|
158
|
-
this.validateSessionId();
|
|
159
|
-
return this.makeRequest(
|
|
160
|
-
"GET",
|
|
161
|
-
`/${this.version}/sessions/${this.sessionId}/players/${track.guild_id}/track/lyrics?skipTrackSource=false`
|
|
162
|
-
);
|
|
163
159
|
}
|
|
164
160
|
}
|
|
165
161
|
|