aqualink 3.0.0 → 3.2.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 +67 -66
- package/build/index.d.ts +171 -134
- package/build/index.js +3 -3
- package/build/structures/Aqua.js +76 -44
- package/build/structures/AquaRecovery.js +48 -13
- package/build/structures/AqualinkEvents.js +2 -0
- package/build/structures/Connection.js +21 -2
- package/build/structures/ConnectionRecovery.js +36 -44
- package/build/structures/Filters.js +3 -1
- package/build/structures/Node.js +266 -124
- package/build/structures/Player.js +146 -66
- package/build/structures/PlayerLifecycle.js +24 -6
- package/build/structures/Queue.js +5 -1
- package/build/structures/Reporting.js +12 -0
- package/build/structures/Rest.js +74 -51
- package/build/structures/Track.js +10 -3
- package/package.json +70 -70
package/build/structures/Rest.js
CHANGED
|
@@ -11,10 +11,7 @@ const {
|
|
|
11
11
|
zstdDecompressSync
|
|
12
12
|
} = require('node:zlib')
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
autoplayModule = require('../handlers/autoplay')
|
|
17
|
-
} catch {}
|
|
14
|
+
const { emitOperationalError } = require('./Reporting')
|
|
18
15
|
|
|
19
16
|
const unrefTimer = (t) => {
|
|
20
17
|
try {
|
|
@@ -90,7 +87,6 @@ const _functions = {
|
|
|
90
87
|
parseBody(data, contentType, forceJson) {
|
|
91
88
|
const isJson = forceJson || this.isJsonContent(contentType)
|
|
92
89
|
if (isJson) {
|
|
93
|
-
if (typeof data === 'string') return JSON.parse(data)
|
|
94
90
|
return JSON.parse(data)
|
|
95
91
|
}
|
|
96
92
|
return typeof data === 'string' ? data : data.toString(UTF8)
|
|
@@ -134,6 +130,7 @@ class Rest {
|
|
|
134
130
|
this.aqua = aqua
|
|
135
131
|
this.node = node
|
|
136
132
|
this.sessionId = node.sessionId
|
|
133
|
+
this._sessionGeneration = 0
|
|
137
134
|
this.timeout = node.timeout || 30000
|
|
138
135
|
|
|
139
136
|
const protocol = node.ssl ? 'https:' : 'http:'
|
|
@@ -208,21 +205,18 @@ class Rest {
|
|
|
208
205
|
this.agent = new (node.ssl ? HttpsAgent : HttpAgent)(opts)
|
|
209
206
|
this.request = node.ssl ? httpsRequest : httpRequest
|
|
210
207
|
|
|
211
|
-
if (
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
})
|
|
224
|
-
}
|
|
225
|
-
autoplayModule.setSharedAgent(this._autoplayAgent)
|
|
208
|
+
if (node.ssl) {
|
|
209
|
+
this._autoplayAgent = this.agent
|
|
210
|
+
} else {
|
|
211
|
+
this._autoplayAgent = new HttpsAgent({
|
|
212
|
+
keepAlive: true,
|
|
213
|
+
maxSockets: node.maxSockets || 128,
|
|
214
|
+
maxFreeSockets: node.maxFreeSockets || 64,
|
|
215
|
+
freeSocketTimeout: node.freeSocketTimeout || 15000,
|
|
216
|
+
keepAliveMsecs: node.keepAliveMsecs || 500,
|
|
217
|
+
scheduling: 'lifo',
|
|
218
|
+
timeout: this.timeout
|
|
219
|
+
})
|
|
226
220
|
}
|
|
227
221
|
|
|
228
222
|
const origCreate = this.agent.createConnection.bind(this.agent)
|
|
@@ -236,10 +230,18 @@ class Rest {
|
|
|
236
230
|
|
|
237
231
|
setSessionId(sessionId) {
|
|
238
232
|
this.sessionId = sessionId
|
|
233
|
+
this._sessionGeneration++
|
|
239
234
|
}
|
|
240
235
|
|
|
241
|
-
_getSessionPath() {
|
|
236
|
+
_getSessionPath(generation) {
|
|
242
237
|
if (!this.sessionId) throw ERRORS.NO_SESSION
|
|
238
|
+
if (generation != null && generation !== this._sessionGeneration) {
|
|
239
|
+
const staleErr = new Error(
|
|
240
|
+
`Stale session: sessionId was updated (expected gen ${generation}, current ${this._sessionGeneration}) for session ${this.sessionId}`
|
|
241
|
+
)
|
|
242
|
+
staleErr.statusCode = 404
|
|
243
|
+
throw staleErr
|
|
244
|
+
}
|
|
243
245
|
return `${this._apiBase}/sessions/${this.sessionId}`
|
|
244
246
|
}
|
|
245
247
|
|
|
@@ -271,7 +273,7 @@ class Rest {
|
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
|
|
274
|
-
_collectBody(stream, preallocSize = 0) {
|
|
276
|
+
_collectBody(stream, preallocSize = 0, source = stream) {
|
|
275
277
|
return new Promise((resolve, reject) => {
|
|
276
278
|
let done = false
|
|
277
279
|
let size = 0
|
|
@@ -304,7 +306,11 @@ class Rest {
|
|
|
304
306
|
size += chunk.length
|
|
305
307
|
chunks.push(chunk)
|
|
306
308
|
}
|
|
307
|
-
if (size > MAX_RESPONSE_SIZE)
|
|
309
|
+
if (size > MAX_RESPONSE_SIZE) {
|
|
310
|
+
stream.destroy?.(ERRORS.RESPONSE_TOO_LARGE)
|
|
311
|
+
if (source !== stream) source.destroy?.(ERRORS.RESPONSE_TOO_LARGE)
|
|
312
|
+
finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
313
|
+
}
|
|
308
314
|
})
|
|
309
315
|
|
|
310
316
|
stream.once('error', (e) => finish(false, e))
|
|
@@ -414,7 +420,7 @@ class Rest {
|
|
|
414
420
|
|
|
415
421
|
const clInt = cl ? parseInt(cl, 10) : 0
|
|
416
422
|
if (clInt > MAX_RESPONSE_SIZE) {
|
|
417
|
-
res.
|
|
423
|
+
res.destroy(ERRORS.RESPONSE_TOO_LARGE)
|
|
418
424
|
return finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
419
425
|
}
|
|
420
426
|
|
|
@@ -472,7 +478,7 @@ class Rest {
|
|
|
472
478
|
preallocSize = clInt
|
|
473
479
|
}
|
|
474
480
|
|
|
475
|
-
this._collectBody(stream, preallocSize)
|
|
481
|
+
this._collectBody(stream, preallocSize, res)
|
|
476
482
|
.then((buffer) => {
|
|
477
483
|
if (!buffer) return finish(true, null)
|
|
478
484
|
finalize(buffer)
|
|
@@ -482,6 +488,10 @@ class Rest {
|
|
|
482
488
|
)
|
|
483
489
|
|
|
484
490
|
req.once('error', (e) => finish(false, e))
|
|
491
|
+
req.setTimeout(this.timeout, () => {
|
|
492
|
+
req.destroy()
|
|
493
|
+
finish(false, new Error(`Socket timeout: ${this.timeout}ms`))
|
|
494
|
+
})
|
|
485
495
|
timer = setTimeout(
|
|
486
496
|
() => finish(false, new Error(`Request timeout: ${this.timeout}ms`)),
|
|
487
497
|
this.timeout
|
|
@@ -494,13 +504,14 @@ class Rest {
|
|
|
494
504
|
_getH2Session() {
|
|
495
505
|
if (!this._h2 || this._h2.closed || this._h2.destroyed) {
|
|
496
506
|
this._clearH2()
|
|
497
|
-
|
|
507
|
+
const session = http2.connect(this.baseUrl, this._tlsOptions || undefined)
|
|
508
|
+
this._h2 = session
|
|
498
509
|
this._resetH2Timer()
|
|
499
510
|
|
|
500
|
-
const onEnd = () => this._clearH2()
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
511
|
+
const onEnd = () => this._clearH2(session)
|
|
512
|
+
session.once('error', onEnd)
|
|
513
|
+
session.once('close', onEnd)
|
|
514
|
+
session.socket?.unref?.()
|
|
504
515
|
}
|
|
505
516
|
return this._h2
|
|
506
517
|
}
|
|
@@ -511,12 +522,14 @@ class Rest {
|
|
|
511
522
|
this._h2Timer = null
|
|
512
523
|
}
|
|
513
524
|
if (this._h2 && !this._h2.closed && !this._h2.destroyed) {
|
|
514
|
-
|
|
525
|
+
const session = this._h2
|
|
526
|
+
this._h2Timer = setTimeout(() => this._closeH2(session), H2_TIMEOUT)
|
|
515
527
|
unrefTimer(this._h2Timer)
|
|
516
528
|
}
|
|
517
529
|
}
|
|
518
530
|
|
|
519
|
-
_clearH2() {
|
|
531
|
+
_clearH2(session = this._h2) {
|
|
532
|
+
if (session !== this._h2) return
|
|
520
533
|
if (this._h2Timer) {
|
|
521
534
|
clearTimeout(this._h2Timer)
|
|
522
535
|
this._h2Timer = null
|
|
@@ -524,7 +537,8 @@ class Rest {
|
|
|
524
537
|
this._h2 = null
|
|
525
538
|
}
|
|
526
539
|
|
|
527
|
-
_closeH2() {
|
|
540
|
+
_closeH2(session = this._h2) {
|
|
541
|
+
if (session !== this._h2) return
|
|
528
542
|
if (this._h2Timer) {
|
|
529
543
|
clearTimeout(this._h2Timer)
|
|
530
544
|
this._h2Timer = null
|
|
@@ -588,7 +602,7 @@ class Rest {
|
|
|
588
602
|
|
|
589
603
|
const clInt = cl ? parseInt(cl, 10) : 0
|
|
590
604
|
if (clInt > MAX_RESPONSE_SIZE) {
|
|
591
|
-
req.
|
|
605
|
+
req.close(http2.constants.NGHTTP2_CANCEL)
|
|
592
606
|
return finish(false, ERRORS.RESPONSE_TOO_LARGE)
|
|
593
607
|
}
|
|
594
608
|
|
|
@@ -621,7 +635,7 @@ class Rest {
|
|
|
621
635
|
|
|
622
636
|
if (decomp) decomp.once('error', (e) => finish(false, e))
|
|
623
637
|
req.once('error', (e) => finish(false, e))
|
|
624
|
-
this._collectBody(stream, preallocSize)
|
|
638
|
+
this._collectBody(stream, preallocSize, req)
|
|
625
639
|
.then((buffer) => {
|
|
626
640
|
if (!buffer) return finish(true, null)
|
|
627
641
|
finalize(buffer)
|
|
@@ -639,28 +653,33 @@ class Rest {
|
|
|
639
653
|
}
|
|
640
654
|
|
|
641
655
|
async updatePlayer({ guildId, data, noReplace = false }) {
|
|
656
|
+
const gen = this._sessionGeneration
|
|
642
657
|
return this.makeRequest(
|
|
643
658
|
'PATCH',
|
|
644
|
-
`${this._getSessionPath()}/players/${guildId}?noReplace=${noReplace}`,
|
|
659
|
+
`${this._getSessionPath(gen)}/players/${guildId}?noReplace=${noReplace}`,
|
|
645
660
|
data
|
|
646
661
|
)
|
|
647
662
|
}
|
|
648
663
|
|
|
649
664
|
async getPlayer(guildId) {
|
|
665
|
+
const gen = this._sessionGeneration
|
|
650
666
|
return this.makeRequest(
|
|
651
667
|
'GET',
|
|
652
|
-
`${this._getSessionPath()}/players/${guildId}`
|
|
668
|
+
`${this._getSessionPath(gen)}/players/${guildId}`
|
|
653
669
|
)
|
|
654
670
|
}
|
|
655
671
|
|
|
656
672
|
async getPlayers() {
|
|
657
|
-
|
|
673
|
+
const gen = this._sessionGeneration
|
|
674
|
+
return this.makeRequest('GET', `${this._getSessionPath(gen)}/players`)
|
|
658
675
|
}
|
|
659
676
|
|
|
660
|
-
async destroyPlayer(guildId) {
|
|
677
|
+
async destroyPlayer(guildId, abortSignal) {
|
|
678
|
+
const gen = this._sessionGeneration
|
|
679
|
+
if (abortSignal?.aborted) return null
|
|
661
680
|
return this.makeRequest(
|
|
662
681
|
'DELETE',
|
|
663
|
-
`${this._getSessionPath()}/players/${guildId}`
|
|
682
|
+
`${this._getSessionPath(gen)}/players/${guildId}`
|
|
664
683
|
)
|
|
665
684
|
}
|
|
666
685
|
|
|
@@ -725,7 +744,7 @@ class Rest {
|
|
|
725
744
|
const title = track?.info?.title
|
|
726
745
|
|
|
727
746
|
if (!track || (!guildId && !hasEncoded && !title)) {
|
|
728
|
-
this.aqua
|
|
747
|
+
emitOperationalError(this.aqua, this.node, 'Invalid lyrics track object')
|
|
729
748
|
return null
|
|
730
749
|
}
|
|
731
750
|
|
|
@@ -733,9 +752,10 @@ class Rest {
|
|
|
733
752
|
|
|
734
753
|
if (guildId) {
|
|
735
754
|
try {
|
|
755
|
+
const gen = this._sessionGeneration
|
|
736
756
|
const lyrics = await this.makeRequest(
|
|
737
757
|
'GET',
|
|
738
|
-
`${this._getSessionPath()}/players/${guildId}/track/lyrics?skipTrackSource=${skip}`
|
|
758
|
+
`${this._getSessionPath(gen)}/players/${guildId}/track/lyrics?skipTrackSource=${skip}`
|
|
739
759
|
)
|
|
740
760
|
if (this._validLyrics(lyrics)) return lyrics
|
|
741
761
|
} catch {}
|
|
@@ -776,10 +796,11 @@ class Rest {
|
|
|
776
796
|
|
|
777
797
|
async subscribeLiveLyrics(guildId, skipTrackSource = false) {
|
|
778
798
|
try {
|
|
799
|
+
const gen = this._sessionGeneration
|
|
779
800
|
return (
|
|
780
801
|
(await this.makeRequest(
|
|
781
802
|
'POST',
|
|
782
|
-
`${this._getSessionPath()}/players/${guildId}/lyrics/subscribe?skipTrackSource=${skipTrackSource ? 'true' : 'false'}`
|
|
803
|
+
`${this._getSessionPath(gen)}/players/${guildId}/lyrics/subscribe?skipTrackSource=${skipTrackSource ? 'true' : 'false'}`
|
|
783
804
|
)) === null
|
|
784
805
|
)
|
|
785
806
|
} catch {
|
|
@@ -789,10 +810,11 @@ class Rest {
|
|
|
789
810
|
|
|
790
811
|
async unsubscribeLiveLyrics(guildId) {
|
|
791
812
|
try {
|
|
813
|
+
const gen = this._sessionGeneration
|
|
792
814
|
return (
|
|
793
815
|
(await this.makeRequest(
|
|
794
816
|
'DELETE',
|
|
795
|
-
`${this._getSessionPath()}/players/${guildId}/lyrics/subscribe`
|
|
817
|
+
`${this._getSessionPath(gen)}/players/${guildId}/lyrics/subscribe`
|
|
796
818
|
)) === null
|
|
797
819
|
)
|
|
798
820
|
} catch {
|
|
@@ -816,9 +838,10 @@ class Rest {
|
|
|
816
838
|
volume: options.volume !== undefined ? options.volume : 0.8
|
|
817
839
|
}
|
|
818
840
|
|
|
841
|
+
const gen = this._sessionGeneration
|
|
819
842
|
return this.makeRequest(
|
|
820
843
|
'POST',
|
|
821
|
-
|
|
844
|
+
`${this._getSessionPath(gen)}/players/${guildId}/mix`,
|
|
822
845
|
payload
|
|
823
846
|
)
|
|
824
847
|
}
|
|
@@ -826,9 +849,10 @@ class Rest {
|
|
|
826
849
|
async getActiveMixer(guildId) {
|
|
827
850
|
if (!this.node.isNodelink)
|
|
828
851
|
throw new Error('Mixer endpoints are only available on Nodelink nodes')
|
|
852
|
+
const gen = this._sessionGeneration
|
|
829
853
|
const response = await this.makeRequest(
|
|
830
854
|
'GET',
|
|
831
|
-
|
|
855
|
+
`${this._getSessionPath(gen)}/players/${guildId}/mix`
|
|
832
856
|
)
|
|
833
857
|
return response?.mixes || []
|
|
834
858
|
}
|
|
@@ -839,9 +863,10 @@ class Rest {
|
|
|
839
863
|
if (!guildId || !mix || typeof volume !== 'number')
|
|
840
864
|
throw new Error('You forget to set the guild_id, mix or volume options')
|
|
841
865
|
|
|
866
|
+
const gen = this._sessionGeneration
|
|
842
867
|
return this.makeRequest(
|
|
843
868
|
'PATCH',
|
|
844
|
-
|
|
869
|
+
`${this._getSessionPath(gen)}/players/${guildId}/mix/${mix}`,
|
|
845
870
|
{ volume }
|
|
846
871
|
)
|
|
847
872
|
}
|
|
@@ -852,9 +877,10 @@ class Rest {
|
|
|
852
877
|
if (!guildId || !mix)
|
|
853
878
|
throw new Error('You forget to set the guild_id and/or mix options')
|
|
854
879
|
|
|
880
|
+
const gen = this._sessionGeneration
|
|
855
881
|
return this.makeRequest(
|
|
856
882
|
'DELETE',
|
|
857
|
-
|
|
883
|
+
`${this._getSessionPath(gen)}/players/${guildId}/mix/${mix}`
|
|
858
884
|
)
|
|
859
885
|
}
|
|
860
886
|
|
|
@@ -868,9 +894,6 @@ class Rest {
|
|
|
868
894
|
if (autoplayAgent && autoplayAgent !== primaryAgent) {
|
|
869
895
|
autoplayAgent.destroy?.()
|
|
870
896
|
}
|
|
871
|
-
if (autoplayModule?.setSharedAgent && autoplayAgent) {
|
|
872
|
-
autoplayModule.setSharedAgent(null)
|
|
873
|
-
}
|
|
874
897
|
this._closeH2()
|
|
875
898
|
if (this._headerPool) {
|
|
876
899
|
this._headerPool.length = 0
|
|
@@ -9,6 +9,7 @@ const _h = {
|
|
|
9
9
|
class Track {
|
|
10
10
|
constructor(data = {}, requester = null, node = null) {
|
|
11
11
|
const info = data.info || {}
|
|
12
|
+
const pluginInfo = info.pluginInfo || data.pluginInfo || {}
|
|
12
13
|
|
|
13
14
|
this.track = data.track || data.encoded || null
|
|
14
15
|
this.identifier = _h.str(info.identifier)
|
|
@@ -21,14 +22,15 @@ class Track {
|
|
|
21
22
|
this.uri = _h.str(info.uri)
|
|
22
23
|
this.sourceName = _h.str(info.sourceName)
|
|
23
24
|
this.artworkUrl = _h.str(info.artworkUrl)
|
|
24
|
-
this.pluginInfo =
|
|
25
|
+
this.pluginInfo = pluginInfo
|
|
26
|
+
this.isrc = _h.str(info.isrc || pluginInfo.isrc) // ISRC support
|
|
25
27
|
|
|
26
28
|
this.playlist = data.playlist || null
|
|
27
29
|
this.node = node || data.node || null
|
|
28
30
|
this.nodes = data.nodes || null
|
|
29
31
|
this.requester = requester || null
|
|
30
32
|
this._infoCache = null
|
|
31
|
-
this._artworkCache = undefined
|
|
33
|
+
this._artworkCache = undefined
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
get info() {
|
|
@@ -43,7 +45,8 @@ class Track {
|
|
|
43
45
|
title: this.title,
|
|
44
46
|
uri: this.uri,
|
|
45
47
|
sourceName: this.sourceName,
|
|
46
|
-
artworkUrl: this.artworkUrl || this._computeArtwork()
|
|
48
|
+
artworkUrl: this.artworkUrl || this._computeArtwork(),
|
|
49
|
+
isrc: this.isrc || null // exposed here
|
|
47
50
|
})
|
|
48
51
|
return this._infoCache
|
|
49
52
|
}
|
|
@@ -113,6 +116,9 @@ class Track {
|
|
|
113
116
|
this.position = _h.num(fi.position, this.position)
|
|
114
117
|
this.duration = _h.num(fi.length, this.duration)
|
|
115
118
|
this.playlist = found.playlist ?? this.playlist
|
|
119
|
+
this.isrc = _h.str(
|
|
120
|
+
fi.isrc ?? fi.pluginInfo?.isrc ?? found.pluginInfo?.isrc ?? this.isrc
|
|
121
|
+
) // keep ISRC
|
|
116
122
|
this._infoCache = null
|
|
117
123
|
|
|
118
124
|
return this
|
|
@@ -139,6 +145,7 @@ class Track {
|
|
|
139
145
|
this.uri =
|
|
140
146
|
this.sourceName =
|
|
141
147
|
this.artworkUrl =
|
|
148
|
+
this.isrc =
|
|
142
149
|
''
|
|
143
150
|
}
|
|
144
151
|
|
package/package.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "aqualink",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "An Lavalink/Nodelink client, focused in pure performance and features",
|
|
5
|
-
"main": "./build/index.js",
|
|
6
|
-
"types": "./build/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"start": "node ./build/index.js"
|
|
9
|
-
},
|
|
10
|
-
"exports": {
|
|
11
|
-
".": {
|
|
12
|
-
"require": "./build/index.js",
|
|
13
|
-
"import": "./build/index.js",
|
|
14
|
-
"types": "./build/index.d.ts"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
"lavalink",
|
|
19
|
-
"lavalink-client",
|
|
20
|
-
"client-wrapper",
|
|
21
|
-
"discord.js",
|
|
22
|
-
"node.js",
|
|
23
|
-
"audio-streaming",
|
|
24
|
-
"music-bot",
|
|
25
|
-
"discord-integration",
|
|
26
|
-
"high-performance",
|
|
27
|
-
"scalable",
|
|
28
|
-
"nodelink",
|
|
29
|
-
"api",
|
|
30
|
-
"discord",
|
|
31
|
-
"lavalink.js",
|
|
32
|
-
"discord.js",
|
|
33
|
-
"lavalink-api",
|
|
34
|
-
"cross-platform",
|
|
35
|
-
"seamless-integration",
|
|
36
|
-
"community-support",
|
|
37
|
-
"open-source",
|
|
38
|
-
"opus"
|
|
39
|
-
],
|
|
40
|
-
"author": "mushroom0162 (https://github.com/ToddyTheNoobDud)",
|
|
41
|
-
"license": "ISC",
|
|
42
|
-
"repository": {
|
|
43
|
-
"type": "git",
|
|
44
|
-
"url": "git+https://github.com/ToddyTheNoobDud/AquaLink.git"
|
|
45
|
-
},
|
|
46
|
-
"homepage": "https://aqualink-6006388d.mintlify.app/",
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"ws": "^8.
|
|
49
|
-
},
|
|
50
|
-
"contributors": [
|
|
51
|
-
{
|
|
52
|
-
"name": "mushroom0162",
|
|
53
|
-
"url": "https://github.com/ToddyTheNoobDud"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"name": "SoulDevs",
|
|
57
|
-
"url": "https://github.com/SoulDevs"
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"name": "southctrl",
|
|
61
|
-
"url": "https://github.com/southctrl"
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
"maintainers": [
|
|
65
|
-
{
|
|
66
|
-
"name": "mushroom0162",
|
|
67
|
-
"url": "https://github.com/ToddyTheNoobDud"
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "aqualink",
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "An Lavalink/Nodelink client, focused in pure performance and features",
|
|
5
|
+
"main": "./build/index.js",
|
|
6
|
+
"types": "./build/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node ./build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"require": "./build/index.js",
|
|
13
|
+
"import": "./build/index.js",
|
|
14
|
+
"types": "./build/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"lavalink",
|
|
19
|
+
"lavalink-client",
|
|
20
|
+
"client-wrapper",
|
|
21
|
+
"discord.js",
|
|
22
|
+
"node.js",
|
|
23
|
+
"audio-streaming",
|
|
24
|
+
"music-bot",
|
|
25
|
+
"discord-integration",
|
|
26
|
+
"high-performance",
|
|
27
|
+
"scalable",
|
|
28
|
+
"nodelink",
|
|
29
|
+
"api",
|
|
30
|
+
"discord",
|
|
31
|
+
"lavalink.js",
|
|
32
|
+
"discord.js",
|
|
33
|
+
"lavalink-api",
|
|
34
|
+
"cross-platform",
|
|
35
|
+
"seamless-integration",
|
|
36
|
+
"community-support",
|
|
37
|
+
"open-source",
|
|
38
|
+
"opus"
|
|
39
|
+
],
|
|
40
|
+
"author": "mushroom0162 (https://github.com/ToddyTheNoobDud)",
|
|
41
|
+
"license": "ISC",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/ToddyTheNoobDud/AquaLink.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://aqualink-6006388d.mintlify.app/",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"ws": "^8.21.1"
|
|
49
|
+
},
|
|
50
|
+
"contributors": [
|
|
51
|
+
{
|
|
52
|
+
"name": "mushroom0162",
|
|
53
|
+
"url": "https://github.com/ToddyTheNoobDud"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "SoulDevs",
|
|
57
|
+
"url": "https://github.com/SoulDevs"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "southctrl",
|
|
61
|
+
"url": "https://github.com/southctrl"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"maintainers": [
|
|
65
|
+
{
|
|
66
|
+
"name": "mushroom0162",
|
|
67
|
+
"url": "https://github.com/ToddyTheNoobDud"
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|