aqualink 1.7.0-beta3 → 1.7.0-beta5
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 +5 -1
- package/build/handlers/fetchImage.js +12 -21
- package/build/structures/Aqua.js +42 -40
- package/build/structures/Connection.js +87 -92
- package/build/structures/Node.js +23 -54
- package/build/structures/Player.js +90 -64
- package/build/structures/Rest.js +11 -1
- package/build/structures/Track.js +29 -39
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,6 +19,10 @@ This code is based in riffy, but its an 100% Rewrite made from scratch...
|
|
|
19
19
|
- Easy player, node, aqua managing
|
|
20
20
|
- Fast responses from rest and node
|
|
21
21
|
- Playlist support (My mix playlists, youtube playlists, spotify playlists)
|
|
22
|
+
- Lyrics Support by Lavalink
|
|
23
|
+
- https://github.com/topi314/LavaLyrics (RECOMMENDED)
|
|
24
|
+
- https://github.com/DRSchlaubi/lyrics.kt (?)
|
|
25
|
+
- https://github.com/DuncteBot/java-timed-lyrics (RECOMMENDED)
|
|
22
26
|
|
|
23
27
|
# Docs (Wiki)
|
|
24
28
|
- https://github.com/ToddyTheNoobDud/AquaLink/wiki
|
|
@@ -178,4 +182,4 @@ client.aqua.on("nodeError", (node, error) => {
|
|
|
178
182
|
});
|
|
179
183
|
|
|
180
184
|
client.login("Yourtokenhere");
|
|
181
|
-
```
|
|
185
|
+
```
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
const { request } = require("undici");
|
|
2
2
|
|
|
3
3
|
const sourceHandlers = new Map([
|
|
4
|
-
['spotify',
|
|
5
|
-
['youtube',
|
|
4
|
+
['spotify', uri => fetchThumbnail(`https://open.spotify.com/oembed?url=${uri}`)],
|
|
5
|
+
['youtube', identifier => fetchYouTubeThumbnail(identifier)]
|
|
6
6
|
]);
|
|
7
7
|
|
|
8
|
-
const YOUTUBE_URL_TEMPLATE =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const YOUTUBE_QUALITIES = [
|
|
12
|
-
'maxresdefault',
|
|
13
|
-
'hqdefault',
|
|
14
|
-
'mqdefault',
|
|
15
|
-
'default'
|
|
16
|
-
].map(YOUTUBE_URL_TEMPLATE);
|
|
8
|
+
const YOUTUBE_URL_TEMPLATE = quality => id => `https://img.youtube.com/vi/${id}/${quality}.jpg`;
|
|
9
|
+
const YOUTUBE_QUALITIES = ['maxresdefault', 'hqdefault', 'mqdefault', 'default'].map(YOUTUBE_URL_TEMPLATE);
|
|
17
10
|
|
|
18
11
|
async function getImageUrl(info) {
|
|
19
12
|
if (!info?.sourceName || !info?.uri) return null;
|
|
@@ -23,7 +16,8 @@ async function getImageUrl(info) {
|
|
|
23
16
|
|
|
24
17
|
try {
|
|
25
18
|
return await handler(info.uri);
|
|
26
|
-
} catch {
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error('Error fetching image URL:', error);
|
|
27
21
|
return null;
|
|
28
22
|
}
|
|
29
23
|
}
|
|
@@ -32,26 +26,23 @@ async function fetchThumbnail(url) {
|
|
|
32
26
|
try {
|
|
33
27
|
const { body } = await request(url, {
|
|
34
28
|
method: "GET",
|
|
35
|
-
headers: {
|
|
36
|
-
'Accept': 'application/json'
|
|
37
|
-
}
|
|
29
|
+
headers: { 'Accept': 'application/json' }
|
|
38
30
|
});
|
|
39
|
-
|
|
40
31
|
const json = await body.json();
|
|
41
32
|
return json.thumbnail_url || null;
|
|
42
|
-
} catch {
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('Error fetching thumbnail:', error);
|
|
43
35
|
return null;
|
|
44
36
|
}
|
|
45
37
|
}
|
|
46
38
|
|
|
47
39
|
async function fetchYouTubeThumbnail(identifier) {
|
|
48
|
-
const fetchPromises = YOUTUBE_QUALITIES.map(urlFunc =>
|
|
49
|
-
fetchThumbnail(urlFunc(identifier))
|
|
50
|
-
);
|
|
40
|
+
const fetchPromises = YOUTUBE_QUALITIES.map(urlFunc => fetchThumbnail(urlFunc(identifier)));
|
|
51
41
|
|
|
52
42
|
try {
|
|
53
43
|
return await Promise.race(fetchPromises);
|
|
54
|
-
} catch {
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Error fetching YouTube thumbnail:', error);
|
|
55
46
|
return null;
|
|
56
47
|
}
|
|
57
48
|
}
|
package/build/structures/Aqua.js
CHANGED
|
@@ -4,8 +4,9 @@ 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
|
+
|
|
7
8
|
class Aqua extends EventEmitter {
|
|
8
|
-
|
|
9
|
+
/**
|
|
9
10
|
* @param {Object} client - The client instance.
|
|
10
11
|
* @param {Array<Object>} nodes - An array of node configurations.
|
|
11
12
|
* @param {Object} options - Configuration options for Aqua.
|
|
@@ -47,7 +48,6 @@ class Aqua extends EventEmitter {
|
|
|
47
48
|
this.setMaxListeners(0);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
|
|
51
51
|
validateInputs(client, nodes, options) {
|
|
52
52
|
if (!client) throw new Error("Client is required to initialize Aqua");
|
|
53
53
|
if (!Array.isArray(nodes) || !nodes.length) throw new Error(`Nodes must be a non-empty Array (Received ${typeof nodes})`);
|
|
@@ -55,8 +55,7 @@ class Aqua extends EventEmitter {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
get leastUsedNodes() {
|
|
58
|
-
|
|
59
|
-
return activeNodes.length ? activeNodes.sort((a, b) => a.rest.calls - b.rest.calls) : [];
|
|
58
|
+
return [...this.nodeMap.values()].filter(node => node.connected).sort((a, b) => a.rest.calls - b.rest.calls);
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
init(clientId) {
|
|
@@ -78,41 +77,42 @@ class Aqua extends EventEmitter {
|
|
|
78
77
|
this.destroyNode(nodeId); // Ensure no duplicate nodes
|
|
79
78
|
const node = new Node(this, options, this.options);
|
|
80
79
|
this.nodeMap.set(nodeId, node);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
80
|
+
node.connect()
|
|
81
|
+
.then(() => this.emit("nodeCreate", node))
|
|
82
|
+
.catch(error => {
|
|
83
|
+
this.nodeMap.delete(nodeId);
|
|
84
|
+
throw error;
|
|
85
|
+
});
|
|
86
|
+
return node;
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
destroyNode(identifier) {
|
|
92
90
|
const node = this.nodeMap.get(identifier);
|
|
93
91
|
if (!node) return;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
|
|
93
|
+
node.disconnect()
|
|
94
|
+
.then(() => {
|
|
95
|
+
node.removeAllListeners();
|
|
96
|
+
this.nodeMap.delete(identifier);
|
|
97
|
+
this.emit("nodeDestroy", node);
|
|
98
|
+
})
|
|
99
|
+
.catch(error => console.error(`Error destroying node ${identifier}:`, error));
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
updateVoiceState({ d, t }) {
|
|
105
103
|
const player = this.players.get(d.guild_id);
|
|
106
|
-
if (player && (t === "VOICE_SERVER_UPDATE" || t === "VOICE_STATE_UPDATE" && d.user_id === this.clientId)) {
|
|
104
|
+
if (player && (t === "VOICE_SERVER_UPDATE" || (t === "VOICE_STATE_UPDATE" && d.user_id === this.clientId))) {
|
|
107
105
|
player.connection[t === "VOICE_SERVER_UPDATE" ? "setServerUpdate" : "setStateUpdate"](d);
|
|
108
106
|
if (d.status === "disconnected") this.cleanupPlayer(player);
|
|
109
107
|
}
|
|
110
108
|
}
|
|
109
|
+
|
|
111
110
|
fetchRegion(region) {
|
|
112
111
|
if (!region) return this.leastUsedNodes;
|
|
113
112
|
const lowerRegion = region.toLowerCase();
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
return [...this.nodeMap.values()]
|
|
114
|
+
.filter(node => node.connected && node.regions?.includes(lowerRegion))
|
|
115
|
+
.sort((a, b) => this.calculateLoad(a) - this.calculateLoad(b));
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
calculateLoad(node) {
|
|
@@ -125,6 +125,7 @@ class Aqua extends EventEmitter {
|
|
|
125
125
|
this.ensureInitialized();
|
|
126
126
|
const player = this.players.get(options.guildId);
|
|
127
127
|
if (player && player.voiceChannel) return player;
|
|
128
|
+
|
|
128
129
|
const node = options.region ? this.fetchRegion(options.region)[0] : this.leastUsedNodes[0];
|
|
129
130
|
if (!node) throw new Error("No nodes are available");
|
|
130
131
|
return this.createPlayer(node, options);
|
|
@@ -140,22 +141,21 @@ class Aqua extends EventEmitter {
|
|
|
140
141
|
return player;
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
async destroyPlayer(guildId) {
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
async destroyPlayer(guildId) {
|
|
145
|
+
const player = this.players.get(guildId);
|
|
146
|
+
if (!player) return;
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
try {
|
|
149
|
+
await player.clearData(); // Assuming clearData is an async function
|
|
150
|
+
player.removeAllListeners();
|
|
151
|
+
this.players.delete(guildId);
|
|
152
|
+
this.emit("playerDestroy", player);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error(`Error destroying player for guild ${guildId}:`, error);
|
|
155
|
+
}
|
|
155
156
|
}
|
|
156
|
-
}
|
|
157
157
|
|
|
158
|
-
async resolve({ query, source = this.defaultSearchPlatform
|
|
158
|
+
async resolve({ query, source = this.defaultSearchPlatform, requester, nodes }) {
|
|
159
159
|
this.ensureInitialized();
|
|
160
160
|
const requestNode = this.getRequestNode(nodes);
|
|
161
161
|
const formattedQuery = this.formatQuery(query, source);
|
|
@@ -188,11 +188,11 @@ async destroyPlayer(guildId) {
|
|
|
188
188
|
return URL_REGEX.test(query) ? query : `${source}:${query}`;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
async handleNoMatches(rest, query) {
|
|
192
192
|
try {
|
|
193
|
-
const youtubeResponse =
|
|
193
|
+
const youtubeResponse = await rest.makeRequest("GET", `/v4/loadtracks?identifier=https://www.youtube.com/watch?v=${query}`);
|
|
194
194
|
if (["empty", "NO_MATCHES"].includes(youtubeResponse.loadType)) {
|
|
195
|
-
return
|
|
195
|
+
return await rest.makeRequest("GET", `/v4/loadtracks?identifier=https://open.spotify.com/track/${query}`);
|
|
196
196
|
}
|
|
197
197
|
return youtubeResponse;
|
|
198
198
|
} catch (error) {
|
|
@@ -208,10 +208,12 @@ async destroyPlayer(guildId) {
|
|
|
208
208
|
pluginInfo: response.pluginInfo ?? {},
|
|
209
209
|
tracks: [],
|
|
210
210
|
};
|
|
211
|
+
|
|
211
212
|
if (response.loadType === "error" || response.loadType === "LOAD_FAILED") {
|
|
212
213
|
baseResponse.exception = response.data ?? response.exception;
|
|
213
214
|
return baseResponse;
|
|
214
215
|
}
|
|
216
|
+
|
|
215
217
|
const trackFactory = (trackData) => new Track(trackData, requester, requestNode);
|
|
216
218
|
switch (response.loadType) {
|
|
217
219
|
case "track":
|
|
@@ -283,4 +285,4 @@ async destroyPlayer(guildId) {
|
|
|
283
285
|
}
|
|
284
286
|
}
|
|
285
287
|
|
|
286
|
-
module.exports = { Aqua };
|
|
288
|
+
module.exports = { Aqua };
|
|
@@ -1,106 +1,101 @@
|
|
|
1
1
|
class Connection {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
constructor(player) {
|
|
3
|
+
this.player = player;
|
|
4
|
+
this.voice = {
|
|
5
|
+
sessionId: null,
|
|
6
|
+
endpoint: null,
|
|
7
|
+
token: null
|
|
8
|
+
};
|
|
9
|
+
this.region = null;
|
|
10
|
+
this.selfDeaf = false;
|
|
11
|
+
this.selfMute = false;
|
|
12
|
+
this.voiceChannel = player.voiceChannel;
|
|
13
|
+
this.guildId = player.guildId;
|
|
14
|
+
this.aqua = player.aqua;
|
|
15
|
+
this.nodes = player.nodes;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setServerUpdate(data) {
|
|
19
|
+
if (!data?.endpoint) {
|
|
20
|
+
throw new Error("Missing 'endpoint' property");
|
|
14
21
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
|
|
23
|
+
const endpoint = data.endpoint;
|
|
24
|
+
const regionMatch = endpoint.match(/^([a-zA-Z]+)/);
|
|
25
|
+
if (!regionMatch) return;
|
|
26
|
+
|
|
27
|
+
const newRegion = regionMatch[1];
|
|
28
|
+
if (this.region !== newRegion) {
|
|
29
|
+
this.voice.endpoint = endpoint;
|
|
30
|
+
this.voice.token = data.token;
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
`[Player ${this._guildId} - CONNECTION] ${
|
|
37
|
-
prevRegion
|
|
38
|
-
? `Changed Voice Region from ${prevRegion} to ${newRegion}`
|
|
39
|
-
: `Voice Server: ${newRegion}`
|
|
40
|
-
}`
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this._updatePlayerVoiceData();
|
|
32
|
+
const prevRegion = this.region;
|
|
33
|
+
this.region = newRegion;
|
|
34
|
+
|
|
35
|
+
this.aqua.emit(
|
|
36
|
+
"debug",
|
|
37
|
+
`[Player ${this.guildId} - CONNECTION] ${
|
|
38
|
+
prevRegion
|
|
39
|
+
? `Changed Voice Region from ${prevRegion} to ${newRegion}`
|
|
40
|
+
: `Voice Server: ${newRegion}`
|
|
41
|
+
}`
|
|
42
|
+
);
|
|
45
43
|
}
|
|
46
|
-
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const sessionId = data.session_id;
|
|
51
|
-
|
|
52
|
-
if (!channelId || !sessionId) {
|
|
53
|
-
this._cleanup();
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
45
|
+
this._updatePlayerVoiceData();
|
|
46
|
+
}
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.
|
|
48
|
+
setStateUpdate(data) {
|
|
49
|
+
const { channel_id: channelId, session_id: sessionId, self_deaf: selfDeaf, self_mute: selfMute } = data;
|
|
50
|
+
|
|
51
|
+
if (!channelId || !sessionId) {
|
|
52
|
+
this._cleanup();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (this.voiceChannel !== channelId) {
|
|
57
|
+
this.aqua.emit("playerMove", this.voiceChannel, channelId);
|
|
58
|
+
this.voiceChannel = channelId;
|
|
67
59
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
|
|
61
|
+
this.selfDeaf = selfDeaf;
|
|
62
|
+
this.selfMute = selfMute;
|
|
63
|
+
this.voice.sessionId = sessionId;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async _updatePlayerVoiceData() {
|
|
67
|
+
try {
|
|
68
|
+
await this.nodes.rest.updatePlayer({
|
|
69
|
+
guildId: this.guildId,
|
|
72
70
|
data: {
|
|
73
71
|
voice: this.voice,
|
|
74
72
|
volume: this.player.volume
|
|
75
73
|
}
|
|
76
|
-
}).catch(err => {
|
|
77
|
-
this._aqua.emit("apiError", "updatePlayer", err);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
_cleanup() {
|
|
82
|
-
const aqua = this._aqua;
|
|
83
|
-
const channel = this.player.voiceChannel;
|
|
84
|
-
|
|
85
|
-
aqua.emit("playerLeave", channel);
|
|
86
|
-
|
|
87
|
-
this.player.voiceChannel = null;
|
|
88
|
-
this.voiceChannel = null;
|
|
89
|
-
this.player.destroy();
|
|
90
|
-
|
|
91
|
-
aqua.emit("playerDestroy", this.player);
|
|
92
|
-
|
|
93
|
-
Object.assign(this, {
|
|
94
|
-
player: null,
|
|
95
|
-
voice: null,
|
|
96
|
-
region: null,
|
|
97
|
-
selfDeaf: null,
|
|
98
|
-
selfMute: null,
|
|
99
|
-
_guildId: null,
|
|
100
|
-
_aqua: null,
|
|
101
|
-
_nodes: null
|
|
102
74
|
});
|
|
75
|
+
} catch (err) {
|
|
76
|
+
this.aqua.emit("apiError", "updatePlayer", err);
|
|
103
77
|
}
|
|
104
78
|
}
|
|
105
|
-
|
|
106
|
-
|
|
79
|
+
|
|
80
|
+
_cleanup() {
|
|
81
|
+
const { aqua, player, voiceChannel } = this;
|
|
82
|
+
|
|
83
|
+
aqua.emit("playerLeave", voiceChannel);
|
|
84
|
+
|
|
85
|
+
player.voiceChannel = null;
|
|
86
|
+
this.voiceChannel = null;
|
|
87
|
+
player.destroy();
|
|
88
|
+
|
|
89
|
+
aqua.emit("playerDestroy", player);
|
|
90
|
+
this.player = null;
|
|
91
|
+
this.voice = null;
|
|
92
|
+
this.region = null;
|
|
93
|
+
this.selfDeaf = null;
|
|
94
|
+
this.selfMute = null;
|
|
95
|
+
this.guildId = null;
|
|
96
|
+
this.aqua = null;
|
|
97
|
+
this.nodes = null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = { Connection };
|
package/build/structures/Node.js
CHANGED
|
@@ -6,6 +6,8 @@ class Node {
|
|
|
6
6
|
#statsCache = {};
|
|
7
7
|
#lastStatsRequest = 0;
|
|
8
8
|
#reconnectAttempted = 0;
|
|
9
|
+
#reconnectTimeoutId = null;
|
|
10
|
+
|
|
9
11
|
constructor(aqua, nodes, options) {
|
|
10
12
|
const {
|
|
11
13
|
name,
|
|
@@ -43,25 +45,9 @@ class Node {
|
|
|
43
45
|
players: 0,
|
|
44
46
|
playingPlayers: 0,
|
|
45
47
|
uptime: 0,
|
|
46
|
-
memory:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
allocated: 0,
|
|
50
|
-
reservable: 0,
|
|
51
|
-
freePercentage: 0,
|
|
52
|
-
usedPercentage: 0
|
|
53
|
-
}),
|
|
54
|
-
cpu: Object.freeze({
|
|
55
|
-
cores: 0,
|
|
56
|
-
systemLoad: 0,
|
|
57
|
-
lavalinkLoad: 0,
|
|
58
|
-
lavalinkLoadPercentage: 0
|
|
59
|
-
}),
|
|
60
|
-
frameStats: Object.freeze({
|
|
61
|
-
sent: 0,
|
|
62
|
-
nulled: 0,
|
|
63
|
-
deficit: 0
|
|
64
|
-
}),
|
|
48
|
+
memory: { free: 0, used: 0, allocated: 0, reservable: 0, freePercentage: 0, usedPercentage: 0 },
|
|
49
|
+
cpu: { cores: 0, systemLoad: 0, lavalinkLoad: 0, lavalinkLoadPercentage: 0 },
|
|
50
|
+
frameStats: { sent: null, nulled: null, deficit: null },
|
|
65
51
|
ping: 0
|
|
66
52
|
};
|
|
67
53
|
}
|
|
@@ -83,14 +69,9 @@ class Node {
|
|
|
83
69
|
|
|
84
70
|
#cleanup() {
|
|
85
71
|
if (this.#ws) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
} catch (err) {
|
|
90
|
-
this.aqua.emit('debug', `Cleanup error: ${err.message}`);
|
|
91
|
-
} finally {
|
|
92
|
-
this.#ws = null;
|
|
93
|
-
}
|
|
72
|
+
this.#ws.removeAllListeners();
|
|
73
|
+
this.#ws.terminate();
|
|
74
|
+
this.#ws = null;
|
|
94
75
|
}
|
|
95
76
|
}
|
|
96
77
|
|
|
@@ -107,11 +88,10 @@ class Node {
|
|
|
107
88
|
|
|
108
89
|
#setupWebSocketListeners() {
|
|
109
90
|
if (!this.#ws) return;
|
|
110
|
-
|
|
111
|
-
ws.once("
|
|
112
|
-
ws.
|
|
113
|
-
ws.
|
|
114
|
-
ws.once("close", this.#onClose.bind(this));
|
|
91
|
+
this.#ws.once("open", this.#onOpen.bind(this));
|
|
92
|
+
this.#ws.once("error", this.#onError.bind(this));
|
|
93
|
+
this.#ws.on("message", this.#onMessage.bind(this));
|
|
94
|
+
this.#ws.once("close", this.#onClose.bind(this));
|
|
115
95
|
}
|
|
116
96
|
|
|
117
97
|
async #onOpen() {
|
|
@@ -119,11 +99,12 @@ class Node {
|
|
|
119
99
|
this.aqua.emit('debug', this.name, `Connected to ${this.wsUrl.href}`);
|
|
120
100
|
try {
|
|
121
101
|
this.info = await this.rest.makeRequest("GET", "/v4/info");
|
|
122
|
-
this.autoResume
|
|
102
|
+
if (this.autoResume) await this.resumePlayers();
|
|
123
103
|
} catch (err) {
|
|
124
104
|
this.info = null;
|
|
125
|
-
!this.aqua.bypassChecks?.nodeFetchInfo
|
|
105
|
+
if (!this.aqua.bypassChecks?.nodeFetchInfo) {
|
|
126
106
|
this.aqua.emit('error', `Failed to fetch node info: ${err.message}`);
|
|
107
|
+
}
|
|
127
108
|
}
|
|
128
109
|
}
|
|
129
110
|
|
|
@@ -147,7 +128,7 @@ class Node {
|
|
|
147
128
|
|
|
148
129
|
#updateStats(payload) {
|
|
149
130
|
if (!payload) return;
|
|
150
|
-
|
|
131
|
+
this.stats = Object.freeze({
|
|
151
132
|
players: payload.players ?? 0,
|
|
152
133
|
playingPlayers: payload.playingPlayers ?? 0,
|
|
153
134
|
uptime: payload.uptime ?? 0,
|
|
@@ -155,8 +136,7 @@ class Node {
|
|
|
155
136
|
memory: this.#updateMemoryStats(payload.memory),
|
|
156
137
|
cpu: this.#updateCpuStats(payload.cpu),
|
|
157
138
|
frameStats: this.#updateFrameStats(payload.frameStats)
|
|
158
|
-
};
|
|
159
|
-
this.stats = Object.freeze(newStats);
|
|
139
|
+
});
|
|
160
140
|
}
|
|
161
141
|
|
|
162
142
|
#updateMemoryStats(memory = {}) {
|
|
@@ -191,11 +171,6 @@ class Node {
|
|
|
191
171
|
deficit: 0
|
|
192
172
|
});
|
|
193
173
|
}
|
|
194
|
-
return Object.freeze({
|
|
195
|
-
sent: frameStats.sent ?? 0,
|
|
196
|
-
nulled: frameStats.nulled ?? 0,
|
|
197
|
-
deficit: frameStats.deficit ?? 0
|
|
198
|
-
});
|
|
199
174
|
}
|
|
200
175
|
|
|
201
176
|
#onMessage(msg) {
|
|
@@ -242,23 +217,18 @@ class Node {
|
|
|
242
217
|
|
|
243
218
|
#reconnect() {
|
|
244
219
|
if (this.infiniteReconnects) {
|
|
245
|
-
this.aqua.emit("nodeReconnect", this,
|
|
246
|
-
setTimeout(() =>
|
|
247
|
-
this.connect();
|
|
248
|
-
}, 10000);
|
|
220
|
+
this.aqua.emit("nodeReconnect", this, "Experimental infinite reconnects enabled, will be trying non-stop...");
|
|
221
|
+
setTimeout(() => this.connect(), 10000);
|
|
249
222
|
return;
|
|
250
223
|
}
|
|
251
224
|
|
|
252
|
-
|
|
253
|
-
clearTimeout(this.reconnectTimeoutId);
|
|
254
|
-
}
|
|
225
|
+
clearTimeout(this.#reconnectTimeoutId);
|
|
255
226
|
if (++this.#reconnectAttempted >= this.reconnectTries) {
|
|
256
227
|
this.aqua.emit("nodeError", this, new Error(`Max reconnection attempts reached (${this.reconnectTries})`));
|
|
257
|
-
clearTimeout(this.reconnectTimeoutId);
|
|
258
228
|
return this.destroy();
|
|
259
229
|
}
|
|
260
|
-
|
|
261
|
-
this
|
|
230
|
+
|
|
231
|
+
this.#reconnectTimeoutId = setTimeout(() => {
|
|
262
232
|
this.aqua.emit("nodeReconnect", this, this.#reconnectAttempted);
|
|
263
233
|
this.connect();
|
|
264
234
|
}, this.reconnectTimeout * Math.pow(2, this.#reconnectAttempted)); // Exponential backoff
|
|
@@ -271,8 +241,7 @@ class Node {
|
|
|
271
241
|
penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10);
|
|
272
242
|
}
|
|
273
243
|
if (this.stats.frameStats) {
|
|
274
|
-
penalties += this.stats.frameStats.deficit;
|
|
275
|
-
penalties += this.stats.frameStats.nulled * 2;
|
|
244
|
+
penalties += this.stats.frameStats.deficit + this.stats.frameStats.nulled * 2;
|
|
276
245
|
}
|
|
277
246
|
return penalties;
|
|
278
247
|
}
|
|
@@ -4,6 +4,11 @@ const { Queue } = require("./Queue");
|
|
|
4
4
|
const { Filters } = require("./Filters");
|
|
5
5
|
|
|
6
6
|
class Player extends EventEmitter {
|
|
7
|
+
static LOOP_MODES = Object.freeze({
|
|
8
|
+
NONE: "none",
|
|
9
|
+
TRACK: "track",
|
|
10
|
+
QUEUE: "queue"
|
|
11
|
+
});
|
|
7
12
|
constructor(aqua, nodes, options = {}) {
|
|
8
13
|
super();
|
|
9
14
|
this.aqua = aqua;
|
|
@@ -30,23 +35,23 @@ class Player extends EventEmitter {
|
|
|
30
35
|
this.previousTracks = [];
|
|
31
36
|
this.shouldDeleteMessage = options.shouldDeleteMessage ?? true;
|
|
32
37
|
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
38
|
+
this.boundHandleEvent = this.handleEvent.bind(this);
|
|
39
|
+
this.boundOnPlayerUpdate = this.onPlayerUpdate.bind(this);
|
|
40
|
+
this.on("playerUpdate", this.boundOnPlayerUpdate);
|
|
41
|
+
this.on("event", this.boundHandleEvent);
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
onPlayerUpdate(
|
|
38
|
-
if (!
|
|
39
|
-
|
|
44
|
+
onPlayerUpdate({ state } = {}) {
|
|
45
|
+
if (!state) return;
|
|
46
|
+
|
|
40
47
|
const { connected, position, ping, time } = state;
|
|
41
|
-
this
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
this.timestamp = time;
|
|
45
|
-
this.aqua.emit("playerUpdate", this, packet);
|
|
48
|
+
Object.assign(this, { connected, position, ping, timestamp: time });
|
|
49
|
+
|
|
50
|
+
this.aqua.emit("playerUpdate", this, { state });
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
get previous() {
|
|
49
|
-
return this.previousTracks
|
|
54
|
+
return this.previousTracks[0] || null;
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
get currenttrack() {
|
|
@@ -60,25 +65,28 @@ class Player extends EventEmitter {
|
|
|
60
65
|
this.previousTracks.unshift(track);
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
|
|
64
68
|
async play() {
|
|
65
|
-
if (!this.connected)
|
|
69
|
+
if (!this.connected) {
|
|
70
|
+
throw new Error("Player must be connected first.");
|
|
71
|
+
}
|
|
66
72
|
if (!this.queue.length) return;
|
|
67
|
-
|
|
73
|
+
|
|
68
74
|
const track = this.queue.shift();
|
|
69
|
-
|
|
70
75
|
this.current = track.track ? track : await track.resolve(this.aqua);
|
|
71
76
|
|
|
72
|
-
this
|
|
73
|
-
|
|
77
|
+
Object.assign(this, {
|
|
78
|
+
playing: true,
|
|
79
|
+
position: 0
|
|
80
|
+
});
|
|
81
|
+
|
|
74
82
|
this.aqua.emit("debug", this.guildId, `Playing track: ${this.current.track}`);
|
|
75
|
-
this.updatePlayer({ track: { encoded: this.current.track } });
|
|
76
|
-
return this;
|
|
83
|
+
return this.updatePlayer({ track: { encoded: this.current.track } });
|
|
77
84
|
}
|
|
78
85
|
|
|
79
|
-
connect(
|
|
80
|
-
if (this.connected)
|
|
81
|
-
|
|
86
|
+
connect({ guildId, voiceChannel, deaf = true, mute = false }) {
|
|
87
|
+
if (this.connected) {
|
|
88
|
+
throw new Error("Player is already connected.");
|
|
89
|
+
}
|
|
82
90
|
this.send({
|
|
83
91
|
guild_id: guildId,
|
|
84
92
|
channel_id: voiceChannel,
|
|
@@ -93,7 +101,7 @@ class Player extends EventEmitter {
|
|
|
93
101
|
destroy() {
|
|
94
102
|
if (!this.connected) return this;
|
|
95
103
|
this.disconnect();
|
|
96
|
-
this.nowPlayingMessage?.delete().catch(() => { });
|
|
104
|
+
this.nowPlayingMessage?.delete().catch(() => { });
|
|
97
105
|
this.aqua.destroyPlayer(this.guildId);
|
|
98
106
|
this.nodes.rest.destroyPlayer(this.guildId);
|
|
99
107
|
return this;
|
|
@@ -105,8 +113,31 @@ class Player extends EventEmitter {
|
|
|
105
113
|
return this;
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
async searchLyrics(query) {
|
|
117
|
+
if (!query) return null;
|
|
118
|
+
const response = await this.nodes.rest.getLyrics({
|
|
119
|
+
track: {
|
|
120
|
+
encoded: { info: { title: query } },
|
|
121
|
+
guild_id: this.guildId,
|
|
122
|
+
search: true
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return response || null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async lyrics() {
|
|
129
|
+
if (!this.playing) return null;
|
|
130
|
+
const response = await this.nodes.rest.getLyrics({
|
|
131
|
+
track: {
|
|
132
|
+
encoded: this.current.track,
|
|
133
|
+
guild_id: this.guildId
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
return response || null;
|
|
137
|
+
}
|
|
138
|
+
|
|
108
139
|
seek(position) {
|
|
109
|
-
if (!this.playing) return this;
|
|
140
|
+
if (!this.playing) return this;
|
|
110
141
|
const newPosition = this.position + position;
|
|
111
142
|
if (newPosition < 0) {
|
|
112
143
|
throw new Error("Seek position cannot be negative.");
|
|
@@ -131,8 +162,7 @@ class Player extends EventEmitter {
|
|
|
131
162
|
return this;
|
|
132
163
|
}
|
|
133
164
|
|
|
134
|
-
static validModes = new Set(["none", "track", "queue"]);
|
|
135
|
-
|
|
165
|
+
static validModes = new Set(["none", "track", "queue"]);
|
|
136
166
|
setLoop(mode) {
|
|
137
167
|
if (!Player.validModes.has(mode)) throw new Error("Loop mode must be 'none', 'track', or 'queue'.");
|
|
138
168
|
this.loop = mode;
|
|
@@ -168,10 +198,10 @@ class Player extends EventEmitter {
|
|
|
168
198
|
}
|
|
169
199
|
|
|
170
200
|
shuffle() {
|
|
171
|
-
const
|
|
172
|
-
for (let i =
|
|
173
|
-
const j =
|
|
174
|
-
[
|
|
201
|
+
const arr = this.queue;
|
|
202
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
203
|
+
const j = (Math.random() * (i + 1)) | 0;
|
|
204
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
175
205
|
}
|
|
176
206
|
return this;
|
|
177
207
|
}
|
|
@@ -189,30 +219,29 @@ class Player extends EventEmitter {
|
|
|
189
219
|
return this.playing ? this.play() : undefined;
|
|
190
220
|
}
|
|
191
221
|
|
|
192
|
-
static EVENT_HANDLERS =
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
222
|
+
static EVENT_HANDLERS = Object.freeze({
|
|
223
|
+
TrackStartEvent: "trackStart",
|
|
224
|
+
TrackEndEvent: "trackEnd",
|
|
225
|
+
TrackExceptionEvent: "trackError",
|
|
226
|
+
TrackStuckEvent: "trackStuck",
|
|
227
|
+
TrackChangeEvent: "trackChange",
|
|
228
|
+
WebSocketClosedEvent: "socketClosed"
|
|
229
|
+
});
|
|
200
230
|
|
|
201
|
-
handleEvent
|
|
231
|
+
async handleEvent(payload) {
|
|
202
232
|
const player = this.aqua.players.get(payload.guildId);
|
|
203
233
|
if (!player) return;
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
207
|
-
this[
|
|
234
|
+
|
|
235
|
+
const handler = Player.EVENT_HANDLERS[payload.type];
|
|
236
|
+
if (handler) {
|
|
237
|
+
await this[handler](player, this.current, payload);
|
|
208
238
|
} else {
|
|
209
|
-
this.handleUnknownEvent(
|
|
239
|
+
this.handleUnknownEvent(payload);
|
|
210
240
|
}
|
|
211
|
-
}
|
|
241
|
+
}
|
|
212
242
|
|
|
213
243
|
trackStart(player, track) {
|
|
214
|
-
this
|
|
215
|
-
this.paused = false;
|
|
244
|
+
Object.assign(this, { playing: true, paused: false });
|
|
216
245
|
this.aqua.emit("trackStart", player, track);
|
|
217
246
|
}
|
|
218
247
|
|
|
@@ -224,36 +253,34 @@ class Player extends EventEmitter {
|
|
|
224
253
|
|
|
225
254
|
async trackEnd(player, track, payload) {
|
|
226
255
|
if (this.shouldDeleteMessage && this.nowPlayingMessage) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
} catch (error) {
|
|
230
|
-
} finally {
|
|
231
|
-
this.nowPlayingMessage = null;
|
|
232
|
-
}
|
|
256
|
+
await this.nowPlayingMessage?.delete().catch(() => { });
|
|
257
|
+
this.nowPlayingMessage = null;
|
|
233
258
|
}
|
|
259
|
+
|
|
234
260
|
const reason = payload.reason.replace("_", "").toLowerCase();
|
|
235
261
|
if (reason === "loadfailed" || reason === "cleanup") {
|
|
236
|
-
|
|
237
|
-
this.aqua.emit("queueEnd", player)
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
return player.play();
|
|
262
|
+
return player.queue.isEmpty() ?
|
|
263
|
+
this.aqua.emit("queueEnd", player) :
|
|
264
|
+
player.play();
|
|
241
265
|
}
|
|
266
|
+
|
|
242
267
|
switch (this.loop) {
|
|
243
|
-
case
|
|
268
|
+
case Player.LOOP_MODES.TRACK:
|
|
244
269
|
this.aqua.emit("trackRepeat", player, track);
|
|
245
270
|
player.queue.unshift(track);
|
|
246
271
|
break;
|
|
247
|
-
case
|
|
272
|
+
case Player.LOOP_MODES.QUEUE:
|
|
248
273
|
this.aqua.emit("queueRepeat", player, track);
|
|
249
274
|
player.queue.push(track);
|
|
250
275
|
break;
|
|
251
276
|
}
|
|
277
|
+
|
|
252
278
|
if (player.queue.isEmpty()) {
|
|
253
279
|
this.playing = false;
|
|
254
280
|
this.aqua.emit("queueEnd", player);
|
|
255
281
|
return this.cleanup();
|
|
256
282
|
}
|
|
283
|
+
|
|
257
284
|
return player.play();
|
|
258
285
|
}
|
|
259
286
|
|
|
@@ -285,9 +312,8 @@ class Player extends EventEmitter {
|
|
|
285
312
|
this.aqua.send({ op: 4, d: data });
|
|
286
313
|
}
|
|
287
314
|
|
|
288
|
-
#dataStore = new
|
|
289
|
-
|
|
290
|
-
set(key, value) {
|
|
315
|
+
#dataStore = new Map();
|
|
316
|
+
set(key, value) {
|
|
291
317
|
this.#dataStore.set(key, value);
|
|
292
318
|
}
|
|
293
319
|
|
|
@@ -296,7 +322,7 @@ class Player extends EventEmitter {
|
|
|
296
322
|
}
|
|
297
323
|
|
|
298
324
|
clearData() {
|
|
299
|
-
this.#dataStore.
|
|
325
|
+
this.#dataStore.clear();
|
|
300
326
|
return this;
|
|
301
327
|
}
|
|
302
328
|
|
package/build/structures/Rest.js
CHANGED
|
@@ -96,6 +96,16 @@ class Rest {
|
|
|
96
96
|
getRoutePlannerAddress(address) {
|
|
97
97
|
return this.makeRequest("POST", `/${this.version}/routeplanner/free/address`, { address });
|
|
98
98
|
}
|
|
99
|
+
async getLyrics({ track }) {
|
|
100
|
+
if (track.search) {
|
|
101
|
+
const v2 = await this.makeRequest("GET", `/v4/lyrics/search?query=${track.encoded.info.title}&source=genius`);
|
|
102
|
+
if (v2) {
|
|
103
|
+
return v2;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const v4 = await this.makeRequest("GET", `/v4/sessions/${this.sessionId}/players/${track.guild_id}/track/lyrics?skipTrackSource=false`);
|
|
107
|
+
return v4;
|
|
108
|
+
}
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
module.exports = { Rest };
|
|
111
|
+
module.exports = { Rest };
|
|
@@ -13,22 +13,22 @@ class Track {
|
|
|
13
13
|
* @param {Node} nodes
|
|
14
14
|
*/
|
|
15
15
|
constructor(data, requester, nodes) {
|
|
16
|
-
const info = data
|
|
16
|
+
const { info = {}, encoded = null, playlist = null } = data || {};
|
|
17
17
|
|
|
18
|
-
this.info = {
|
|
18
|
+
this.info = Object.freeze({
|
|
19
19
|
identifier: info.identifier || '',
|
|
20
|
-
isSeekable:
|
|
20
|
+
isSeekable: Boolean(info.isSeekable),
|
|
21
21
|
author: info.author || '',
|
|
22
|
-
length:
|
|
23
|
-
isStream:
|
|
22
|
+
length: info.length | 0,
|
|
23
|
+
isStream: Boolean(info.isStream),
|
|
24
24
|
title: info.title || '',
|
|
25
25
|
uri: info.uri || '',
|
|
26
26
|
sourceName: info.sourceName || '',
|
|
27
27
|
artworkUrl: info.artworkUrl || ''
|
|
28
|
-
};
|
|
28
|
+
});
|
|
29
29
|
|
|
30
|
-
this.track =
|
|
31
|
-
this.playlist =
|
|
30
|
+
this.track = encoded;
|
|
31
|
+
this.playlist = playlist;
|
|
32
32
|
this.requester = requester;
|
|
33
33
|
this.nodes = nodes;
|
|
34
34
|
}
|
|
@@ -38,8 +38,9 @@ class Track {
|
|
|
38
38
|
* @returns {string|null}
|
|
39
39
|
*/
|
|
40
40
|
resolveThumbnail(thumbnail) {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
return thumbnail && thumbnail.startsWith("http") ?
|
|
42
|
+
thumbnail :
|
|
43
|
+
thumbnail ? getImageUrl(thumbnail, this.nodes) : null;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -47,12 +48,14 @@ class Track {
|
|
|
47
48
|
* @returns {Promise<Track|null>}
|
|
48
49
|
*/
|
|
49
50
|
async resolve(aqua) {
|
|
50
|
-
|
|
51
|
+
const searchPlatform = aqua?.options?.defaultSearchPlatform;
|
|
52
|
+
if (!searchPlatform) return null;
|
|
51
53
|
|
|
52
54
|
try {
|
|
55
|
+
const query = `${this.info.author} - ${this.info.title}`;
|
|
53
56
|
const result = await aqua.resolve({
|
|
54
|
-
query
|
|
55
|
-
source:
|
|
57
|
+
query,
|
|
58
|
+
source: searchPlatform,
|
|
56
59
|
requester: this.requester,
|
|
57
60
|
node: this.nodes
|
|
58
61
|
});
|
|
@@ -62,7 +65,10 @@ class Track {
|
|
|
62
65
|
const track = this._findMatchingTrack(result.tracks);
|
|
63
66
|
if (!track) return null;
|
|
64
67
|
|
|
65
|
-
this.
|
|
68
|
+
this.info.identifier = track.info.identifier;
|
|
69
|
+
this.track = track.track;
|
|
70
|
+
this.playlist = track.playlist || null;
|
|
71
|
+
|
|
66
72
|
return this;
|
|
67
73
|
} catch {
|
|
68
74
|
return null;
|
|
@@ -74,40 +80,24 @@ class Track {
|
|
|
74
80
|
*/
|
|
75
81
|
_findMatchingTrack(tracks) {
|
|
76
82
|
const { author, title, length } = this.info;
|
|
77
|
-
|
|
78
|
-
for (
|
|
79
|
-
const track = tracks[i];
|
|
83
|
+
|
|
84
|
+
for (const track of tracks) {
|
|
80
85
|
const tInfo = track.info;
|
|
81
86
|
|
|
82
|
-
if (tInfo.author
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
if (!author || !title || author !== tInfo.author || title !== tInfo.title) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!length || Math.abs(tInfo.length - length) <= 2000) {
|
|
85
92
|
return track;
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
return tracks[0];
|
|
90
97
|
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* @private
|
|
94
|
-
*/
|
|
95
|
-
_updateTrack(track) {
|
|
96
|
-
this.info.identifier = track.info.identifier;
|
|
97
|
-
this.track = track.track;
|
|
98
|
-
this.playlist = track.playlist || null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Fast cleanup
|
|
103
|
-
*/
|
|
104
98
|
destroy() {
|
|
105
|
-
this.
|
|
106
|
-
this.nodes = null;
|
|
107
|
-
this.track = null;
|
|
108
|
-
this.playlist = null;
|
|
109
|
-
this.info = null;
|
|
99
|
+
Object.keys(this).forEach(key => this[key] = null);
|
|
110
100
|
}
|
|
111
101
|
}
|
|
112
102
|
|
|
113
|
-
module.exports = { Track };
|
|
103
|
+
module.exports = { Track };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aqualink",
|
|
3
|
-
"version": "1.7.0-
|
|
3
|
+
"version": "1.7.0-beta5",
|
|
4
4
|
"description": "An Lavalink wrapper, focused in speed, performance, and features, Based in Riffy!",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"author": "mushroom0162 (https://github.com/ToddyTheNoobDud)",
|
|
37
37
|
"license": "ISC",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"undici": "^7.
|
|
39
|
+
"undici": "^7.3.0",
|
|
40
40
|
"ws": "^8.18.0"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|