aqualink 2.19.0 → 2.20.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/build/handlers/autoplay.js +22 -6
- package/build/handlers/fetchImage.js +2 -4
- package/build/index.d.ts +383 -5
- package/build/index.js +48 -0
- package/build/structures/Aqua.js +265 -74
- package/build/structures/AqualinkEvents.js +0 -2
- package/build/structures/Connection.js +145 -24
- package/build/structures/Filters.js +53 -5
- package/build/structures/Node.js +40 -5
- package/build/structures/Player.js +166 -58
- package/build/structures/Plugins.js +2 -2
- package/build/structures/Queue.js +13 -12
- package/build/structures/Rest.js +159 -142
- package/build/structures/Track.js +13 -6
- package/package.json +3 -4
package/build/structures/Rest.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
const
|
|
5
|
-
const { Agent: HttpAgent, request: httpRequest } = require('http')
|
|
6
|
-
const http2 = require('http2')
|
|
1
|
+
const { Buffer } = require('node:buffer')
|
|
2
|
+
const { Agent: HttpsAgent, request: httpsRequest } = require('node:https')
|
|
3
|
+
const { Agent: HttpAgent, request: httpRequest } = require('node:http')
|
|
4
|
+
const http2 = require('node:http2')
|
|
7
5
|
const {
|
|
8
6
|
createBrotliDecompress,
|
|
9
7
|
createUnzip,
|
|
@@ -11,7 +9,12 @@ const {
|
|
|
11
9
|
unzipSync,
|
|
12
10
|
createZstdDecompress,
|
|
13
11
|
zstdDecompressSync
|
|
14
|
-
} = require('zlib')
|
|
12
|
+
} = require('node:zlib')
|
|
13
|
+
|
|
14
|
+
let autoplayModule = null
|
|
15
|
+
try {
|
|
16
|
+
autoplayModule = require('../handlers/autoplay')
|
|
17
|
+
} catch {}
|
|
15
18
|
|
|
16
19
|
const unrefTimer = (t) => {
|
|
17
20
|
try {
|
|
@@ -147,7 +150,7 @@ class Rest {
|
|
|
147
150
|
decodetracks: `${this._apiBase}/decodetracks`,
|
|
148
151
|
stats: `${this._apiBase}/stats`,
|
|
149
152
|
info: `${this._apiBase}/info`,
|
|
150
|
-
version:
|
|
153
|
+
version: `/version`,
|
|
151
154
|
routeplanner: Object.freeze({
|
|
152
155
|
status: `${this._apiBase}/routeplanner/status`,
|
|
153
156
|
freeAddress: `${this._apiBase}/routeplanner/free/address`,
|
|
@@ -173,6 +176,7 @@ class Rest {
|
|
|
173
176
|
this.useHttp2 = !!aqua?.options?.useHttp2
|
|
174
177
|
this._h2 = null
|
|
175
178
|
this._h2Timer = null
|
|
179
|
+
this.calls = 0
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
_setupAgent(node) {
|
|
@@ -203,6 +207,10 @@ class Rest {
|
|
|
203
207
|
this.agent = new (node.ssl ? HttpsAgent : HttpAgent)(opts)
|
|
204
208
|
this.request = node.ssl ? httpsRequest : httpRequest
|
|
205
209
|
|
|
210
|
+
if (node.ssl && autoplayModule?.setSharedAgent) {
|
|
211
|
+
autoplayModule.setSharedAgent(this.agent)
|
|
212
|
+
}
|
|
213
|
+
|
|
206
214
|
const origCreate = this.agent.createConnection.bind(this.agent)
|
|
207
215
|
this.agent.createConnection = (options, cb) => {
|
|
208
216
|
const socket = origCreate(options, cb)
|
|
@@ -249,6 +257,88 @@ class Rest {
|
|
|
249
257
|
}
|
|
250
258
|
}
|
|
251
259
|
|
|
260
|
+
_collectBody(stream, preallocSize = 0) {
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
let done = false
|
|
263
|
+
let size = 0
|
|
264
|
+
let prealloc =
|
|
265
|
+
preallocSize > 0 && preallocSize <= MAX_RESPONSE_SIZE
|
|
266
|
+
? Buffer.allocUnsafe(preallocSize)
|
|
267
|
+
: null
|
|
268
|
+
let chunks = prealloc ? null : []
|
|
269
|
+
|
|
270
|
+
const finish = (ok, val) => {
|
|
271
|
+
if (done) return
|
|
272
|
+
done = true
|
|
273
|
+
prealloc = null
|
|
274
|
+
chunks = null
|
|
275
|
+
ok ? resolve(val) : reject(val)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
stream.on('data', (chunk) => {
|
|
279
|
+
if (done) return
|
|
280
|
+
if (prealloc) {
|
|
281
|
+
if (size + chunk.length <= prealloc.length) {
|
|
282
|
+
chunk.copy(prealloc, size)
|
|
283
|
+
size += chunk.length
|
|
284
|
+
} else {
|
|
285
|
+
chunks = [prealloc.slice(0, size), chunk]
|
|
286
|
+
size += chunk.length
|
|
287
|
+
prealloc = null
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
size += chunk.length
|
|
291
|
+
chunks.push(chunk)
|
|
292
|
+
}
|
|
293
|
+
if (size > MAX_RESPONSE_SIZE) finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
stream.once('error', (e) => finish(false, e))
|
|
297
|
+
stream.once('end', () => {
|
|
298
|
+
if (done) return
|
|
299
|
+
if (size === 0) return finish(true, null)
|
|
300
|
+
finish(
|
|
301
|
+
true,
|
|
302
|
+
prealloc
|
|
303
|
+
? prealloc.slice(0, size)
|
|
304
|
+
: chunks.length === 1
|
|
305
|
+
? chunks[0]
|
|
306
|
+
: Buffer.concat(chunks, size)
|
|
307
|
+
)
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
_parseResponseBuffer(
|
|
313
|
+
buffer,
|
|
314
|
+
status,
|
|
315
|
+
method,
|
|
316
|
+
url,
|
|
317
|
+
headers,
|
|
318
|
+
contentType,
|
|
319
|
+
statusMessage
|
|
320
|
+
) {
|
|
321
|
+
if (!buffer) return null
|
|
322
|
+
if (buffer.length > MAX_RESPONSE_SIZE) throw ERRORS.RESPONSE_TOO_LARGE
|
|
323
|
+
let result
|
|
324
|
+
try {
|
|
325
|
+
result = _functions.parseBody(buffer, contentType, false)
|
|
326
|
+
} catch (e) {
|
|
327
|
+
throw new Error(`JSON parse error: ${e.message}`)
|
|
328
|
+
}
|
|
329
|
+
if (status >= 400) {
|
|
330
|
+
throw _functions.createHttpError(
|
|
331
|
+
status,
|
|
332
|
+
method,
|
|
333
|
+
url,
|
|
334
|
+
headers,
|
|
335
|
+
result,
|
|
336
|
+
statusMessage
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
return result
|
|
340
|
+
}
|
|
341
|
+
|
|
252
342
|
async makeRequest(method, endpoint, body) {
|
|
253
343
|
const url = `${this.baseUrl}${endpoint}`
|
|
254
344
|
const payload =
|
|
@@ -259,6 +349,7 @@ class Rest {
|
|
|
259
349
|
: JSON.stringify(body)
|
|
260
350
|
const payloadLen = payload ? Buffer.byteLength(payload, UTF8) : 0
|
|
261
351
|
const headers = this._buildHeaders(!!payload, payloadLen)
|
|
352
|
+
this.calls++
|
|
262
353
|
|
|
263
354
|
try {
|
|
264
355
|
const resp =
|
|
@@ -267,6 +358,7 @@ class Rest {
|
|
|
267
358
|
: await this._h1Request(method, url, headers, payload)
|
|
268
359
|
return resp
|
|
269
360
|
} finally {
|
|
361
|
+
if (this.calls > 0) this.calls--
|
|
270
362
|
this._returnHeaders(headers)
|
|
271
363
|
}
|
|
272
364
|
}
|
|
@@ -276,9 +368,6 @@ class Rest {
|
|
|
276
368
|
let req,
|
|
277
369
|
timer,
|
|
278
370
|
done = false
|
|
279
|
-
let chunks = null,
|
|
280
|
-
size = 0,
|
|
281
|
-
prealloc = null
|
|
282
371
|
|
|
283
372
|
const finish = (ok, val) => {
|
|
284
373
|
if (done) return
|
|
@@ -287,7 +376,6 @@ class Rest {
|
|
|
287
376
|
clearTimeout(timer)
|
|
288
377
|
timer = null
|
|
289
378
|
}
|
|
290
|
-
chunks = prealloc = null
|
|
291
379
|
if (req && !ok) req.destroy()
|
|
292
380
|
ok ? resolve(val) : reject(val)
|
|
293
381
|
}
|
|
@@ -319,104 +407,63 @@ class Rest {
|
|
|
319
407
|
const encoding = _functions.getEncodingType(
|
|
320
408
|
res.headers['content-encoding']
|
|
321
409
|
)
|
|
322
|
-
|
|
323
|
-
const handleResponse = (buffer) => {
|
|
324
|
-
if (buffer.length > MAX_RESPONSE_SIZE)
|
|
325
|
-
return finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
326
|
-
|
|
410
|
+
const finalize = (buffer) => {
|
|
327
411
|
try {
|
|
328
|
-
const result =
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
res.statusMessage
|
|
339
|
-
)
|
|
340
|
-
)
|
|
341
|
-
} else {
|
|
342
|
-
finish(true, result)
|
|
343
|
-
}
|
|
412
|
+
const result = this._parseResponseBuffer(
|
|
413
|
+
buffer,
|
|
414
|
+
status,
|
|
415
|
+
method,
|
|
416
|
+
url,
|
|
417
|
+
res.headers,
|
|
418
|
+
contentType,
|
|
419
|
+
res.statusMessage
|
|
420
|
+
)
|
|
421
|
+
finish(true, result)
|
|
344
422
|
} catch (e) {
|
|
345
|
-
finish(false,
|
|
423
|
+
finish(false, e)
|
|
346
424
|
}
|
|
347
425
|
}
|
|
348
426
|
|
|
427
|
+
res.once('aborted', () => finish(false, ERRORS.RESPONSE_ABORTED))
|
|
428
|
+
res.once('error', (e) => finish(false, e))
|
|
429
|
+
|
|
349
430
|
if (
|
|
350
431
|
encoding !== ENCODING_NONE &&
|
|
351
432
|
clInt > 0 &&
|
|
352
433
|
clInt < COMPRESSION_MIN_SIZE
|
|
353
434
|
) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
return finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
361
|
-
compressed.push(c)
|
|
362
|
-
})
|
|
363
|
-
res.once('end', () => {
|
|
364
|
-
try {
|
|
365
|
-
handleResponse(
|
|
366
|
-
_functions.decompressSync(Buffer.concat(compressed), encoding)
|
|
435
|
+
this._collectBody(res)
|
|
436
|
+
.then((compressed) => {
|
|
437
|
+
if (!compressed) return finish(true, null)
|
|
438
|
+
const decompressed = _functions.decompressSync(
|
|
439
|
+
compressed,
|
|
440
|
+
encoding
|
|
367
441
|
)
|
|
368
|
-
|
|
442
|
+
finalize(decompressed)
|
|
443
|
+
})
|
|
444
|
+
.catch((e) => {
|
|
369
445
|
finish(false, e)
|
|
370
|
-
}
|
|
371
|
-
})
|
|
372
|
-
res.once('aborted', () => finish(false, ERRORS.RESPONSE_ABORTED))
|
|
373
|
-
res.once('error', (e) => finish(false, e))
|
|
446
|
+
})
|
|
374
447
|
return
|
|
375
448
|
}
|
|
376
449
|
|
|
377
|
-
if (
|
|
378
|
-
encoding === ENCODING_NONE &&
|
|
379
|
-
clInt > 0 &&
|
|
380
|
-
clInt <= MAX_RESPONSE_SIZE
|
|
381
|
-
) {
|
|
382
|
-
prealloc = Buffer.allocUnsafe(clInt)
|
|
383
|
-
} else {
|
|
384
|
-
chunks = []
|
|
385
|
-
}
|
|
386
|
-
|
|
387
450
|
let stream = res
|
|
451
|
+
let preallocSize = 0
|
|
388
452
|
if (encoding !== ENCODING_NONE) {
|
|
389
453
|
const decomp = _functions.createDecompressor(encoding)
|
|
390
454
|
decomp.once('error', (e) => finish(false, e))
|
|
391
455
|
res.pipe(decomp)
|
|
392
456
|
stream = decomp
|
|
457
|
+
} else if (clInt > 0 && clInt <= MAX_RESPONSE_SIZE) {
|
|
458
|
+
preallocSize = clInt
|
|
393
459
|
}
|
|
394
460
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
size += chunk.length
|
|
402
|
-
} else {
|
|
403
|
-
size += chunk.length
|
|
404
|
-
if (size > MAX_RESPONSE_SIZE)
|
|
405
|
-
return finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
406
|
-
chunks.push(chunk)
|
|
407
|
-
}
|
|
408
|
-
})
|
|
409
|
-
|
|
410
|
-
stream.once('end', () => {
|
|
411
|
-
if (size === 0) return finish(true, null)
|
|
412
|
-
handleResponse(
|
|
413
|
-
prealloc
|
|
414
|
-
? prealloc.slice(0, size)
|
|
415
|
-
: chunks.length === 1
|
|
416
|
-
? chunks[0]
|
|
417
|
-
: Buffer.concat(chunks, size)
|
|
418
|
-
)
|
|
419
|
-
})
|
|
461
|
+
this._collectBody(stream, preallocSize)
|
|
462
|
+
.then((buffer) => {
|
|
463
|
+
if (!buffer) return finish(true, null)
|
|
464
|
+
finalize(buffer)
|
|
465
|
+
})
|
|
466
|
+
.catch((e) => finish(false, e))
|
|
420
467
|
}
|
|
421
468
|
)
|
|
422
469
|
|
|
@@ -483,9 +530,6 @@ class Rest {
|
|
|
483
530
|
let req,
|
|
484
531
|
timer,
|
|
485
532
|
done = false
|
|
486
|
-
let chunks = null,
|
|
487
|
-
size = 0,
|
|
488
|
-
prealloc = null
|
|
489
533
|
|
|
490
534
|
const finish = (ok, val) => {
|
|
491
535
|
if (done) return
|
|
@@ -494,7 +538,6 @@ class Rest {
|
|
|
494
538
|
clearTimeout(timer)
|
|
495
539
|
timer = null
|
|
496
540
|
}
|
|
497
|
-
chunks = prealloc = null
|
|
498
541
|
if (req && !ok) req.close(http2.constants.NGHTTP2_CANCEL)
|
|
499
542
|
ok ? resolve(val) : reject(val)
|
|
500
543
|
}
|
|
@@ -536,15 +579,20 @@ class Rest {
|
|
|
536
579
|
}
|
|
537
580
|
|
|
538
581
|
const encoding = _functions.getEncodingType(rh['content-encoding'])
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
582
|
+
const finalize = (buffer) => {
|
|
583
|
+
try {
|
|
584
|
+
const result = this._parseResponseBuffer(
|
|
585
|
+
buffer,
|
|
586
|
+
status,
|
|
587
|
+
method,
|
|
588
|
+
this.baseUrl + path,
|
|
589
|
+
rh,
|
|
590
|
+
contentType
|
|
591
|
+
)
|
|
592
|
+
finish(true, result)
|
|
593
|
+
} catch (e) {
|
|
594
|
+
finish(false, e)
|
|
595
|
+
}
|
|
548
596
|
}
|
|
549
597
|
|
|
550
598
|
const decomp =
|
|
@@ -552,51 +600,19 @@ class Rest {
|
|
|
552
600
|
? _functions.createDecompressor(encoding)
|
|
553
601
|
: null
|
|
554
602
|
const stream = decomp ? req.pipe(decomp) : req
|
|
603
|
+
const preallocSize =
|
|
604
|
+
encoding === ENCODING_NONE && clInt > 0 && clInt <= MAX_RESPONSE_SIZE
|
|
605
|
+
? clInt
|
|
606
|
+
: 0
|
|
555
607
|
|
|
556
608
|
if (decomp) decomp.once('error', (e) => finish(false, e))
|
|
557
609
|
req.once('error', (e) => finish(false, e))
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
size += chunk.length
|
|
565
|
-
if (size > MAX_RESPONSE_SIZE)
|
|
566
|
-
return finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
567
|
-
chunks.push(chunk)
|
|
568
|
-
}
|
|
569
|
-
})
|
|
570
|
-
|
|
571
|
-
stream.once('end', () => {
|
|
572
|
-
if (size === 0) return finish(true, null)
|
|
573
|
-
|
|
574
|
-
const buffer = prealloc
|
|
575
|
-
? prealloc.slice(0, size)
|
|
576
|
-
: chunks.length === 1
|
|
577
|
-
? chunks[0]
|
|
578
|
-
: Buffer.concat(chunks, size)
|
|
579
|
-
|
|
580
|
-
try {
|
|
581
|
-
const result = _functions.parseBody(buffer, contentType, false)
|
|
582
|
-
if (status >= 400) {
|
|
583
|
-
finish(
|
|
584
|
-
false,
|
|
585
|
-
_functions.createHttpError(
|
|
586
|
-
status,
|
|
587
|
-
method,
|
|
588
|
-
this.baseUrl + path,
|
|
589
|
-
rh,
|
|
590
|
-
result
|
|
591
|
-
)
|
|
592
|
-
)
|
|
593
|
-
} else {
|
|
594
|
-
finish(true, result)
|
|
595
|
-
}
|
|
596
|
-
} catch (e) {
|
|
597
|
-
finish(false, new Error(`JSON parse error: ${e.message}`))
|
|
598
|
-
}
|
|
599
|
-
})
|
|
610
|
+
this._collectBody(stream, preallocSize)
|
|
611
|
+
.then((buffer) => {
|
|
612
|
+
if (!buffer) return finish(true, null)
|
|
613
|
+
finalize(buffer)
|
|
614
|
+
})
|
|
615
|
+
.catch((e) => finish(false, e))
|
|
600
616
|
})
|
|
601
617
|
|
|
602
618
|
timer = setTimeout(
|
|
@@ -844,6 +860,7 @@ class Rest {
|
|
|
844
860
|
this.defaultHeaders =
|
|
845
861
|
this._endpoints =
|
|
846
862
|
null
|
|
863
|
+
this.calls = 0
|
|
847
864
|
}
|
|
848
865
|
}
|
|
849
866
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
1
|
const YT_ID_REGEX =
|
|
4
2
|
/(?:[?&]v=|youtu\.be\/|\/embed\/|\/shorts\/)([A-Za-z0-9_-]{11})/
|
|
5
3
|
|
|
@@ -30,10 +28,12 @@ class Track {
|
|
|
30
28
|
this.nodes = data.nodes || null
|
|
31
29
|
this.requester = requester || null
|
|
32
30
|
this._infoCache = null
|
|
31
|
+
this._artworkCache = undefined // undefined = not computed, null = computed but no artwork
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
get info() {
|
|
36
|
-
|
|
35
|
+
if (this._infoCache) return this._infoCache
|
|
36
|
+
this._infoCache = Object.freeze({
|
|
37
37
|
identifier: this.identifier,
|
|
38
38
|
isSeekable: this.isSeekable,
|
|
39
39
|
position: this.position,
|
|
@@ -44,7 +44,8 @@ class Track {
|
|
|
44
44
|
uri: this.uri,
|
|
45
45
|
sourceName: this.sourceName,
|
|
46
46
|
artworkUrl: this.artworkUrl || this._computeArtwork()
|
|
47
|
-
})
|
|
47
|
+
})
|
|
48
|
+
return this._infoCache
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
get length() {
|
|
@@ -52,7 +53,10 @@ class Track {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
get thumbnail() {
|
|
55
|
-
|
|
56
|
+
if (this.artworkUrl) return this.artworkUrl
|
|
57
|
+
if (this._artworkCache !== undefined) return this._artworkCache
|
|
58
|
+
this._artworkCache = this._computeArtwork()
|
|
59
|
+
return this._artworkCache
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
async resolve(aqua, opts = {}) {
|
|
@@ -140,10 +144,13 @@ class Track {
|
|
|
140
144
|
|
|
141
145
|
_computeArtwork() {
|
|
142
146
|
if (this.artworkUrl) return this.artworkUrl
|
|
147
|
+
if (this._artworkCache !== undefined) return this._artworkCache
|
|
143
148
|
const id = this.identifier || (this.uri && YT_ID_REGEX.exec(this.uri)?.[1])
|
|
144
149
|
if (id && this.sourceName?.includes('youtube')) {
|
|
145
|
-
|
|
150
|
+
this._artworkCache = `https://i.ytimg.com/vi/${id}/hqdefault.jpg`
|
|
151
|
+
return this._artworkCache
|
|
146
152
|
}
|
|
153
|
+
this._artworkCache = null
|
|
147
154
|
return null
|
|
148
155
|
}
|
|
149
156
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aqualink",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"description": "An Lavalink/Nodelink client, focused in pure performance and features",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -45,8 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"homepage": "https://aqualink-6006388d.mintlify.app/",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"ws": "^8.19.0"
|
|
49
|
-
"tseep": "^1.3.1"
|
|
48
|
+
"ws": "^8.19.0"
|
|
50
49
|
},
|
|
51
50
|
"contributors": [
|
|
52
51
|
{
|
|
@@ -68,4 +67,4 @@
|
|
|
68
67
|
"url": "https://github.com/ToddyTheNoobDud"
|
|
69
68
|
}
|
|
70
69
|
]
|
|
71
|
-
}
|
|
70
|
+
}
|