magmastream 2.10.3-dev.2 → 2.10.4
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/dist/structures/Enums.d.ts +145 -1
- package/dist/structures/Enums.js +148 -1
- package/dist/structures/Filters.d.ts +120 -1
- package/dist/structures/Filters.js +348 -11
- package/dist/structures/Manager.d.ts +9 -0
- package/dist/structures/Manager.js +169 -30
- package/dist/structures/Node.d.ts +89 -2
- package/dist/structures/Node.js +504 -53
- package/dist/structures/Player.d.ts +85 -2
- package/dist/structures/Player.js +300 -12
- package/dist/structures/Rest.d.ts +61 -2
- package/dist/structures/Rest.js +210 -1
- package/dist/structures/Types.d.ts +645 -90
- package/dist/structures/Utils.d.ts +1 -1
- package/dist/structures/Utils.js +60 -18
- package/dist/utils/managerCheck.js +3 -2
- package/package.json +3 -2
package/dist/structures/Rest.js
CHANGED
|
@@ -55,6 +55,36 @@ class Rest {
|
|
|
55
55
|
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Getting player on node: ${this.node.options.identifier} : ${Utils_1.JSONUtils.safe(result, 2)}`);
|
|
56
56
|
return result;
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Retrieves all players that belong to the current session.
|
|
60
|
+
* @returns {Promise<LavaPlayer[]>} Returns the players.
|
|
61
|
+
*/
|
|
62
|
+
async getPlayers() {
|
|
63
|
+
if (!this.sessionId) {
|
|
64
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Skipping getPlayers - no session ID on node ${this.node.options.identifier}`);
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const result = await this.get(`/v4/sessions/${this.sessionId}/players`);
|
|
69
|
+
return Array.isArray(result) ? result : (result?.players ?? []);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
const shouldFallback = err instanceof MagmastreamError_1.MagmaStreamError && err.code === Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED && err.message.includes("(400)");
|
|
73
|
+
if (!shouldFallback)
|
|
74
|
+
throw err;
|
|
75
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] getPlayers bulk endpoint failed on node ${this.node.options.identifier}; falling back to individual player fetches.`);
|
|
76
|
+
const players = this.manager.players.filter((player) => player.node.options.identifier === this.node.options.identifier);
|
|
77
|
+
const results = await Promise.all(players.map(async (player) => {
|
|
78
|
+
try {
|
|
79
|
+
return await this.getPlayer(player.guildId);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
85
|
+
return results.filter((player) => player !== null);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
58
88
|
/**
|
|
59
89
|
* Sends a PATCH request to update player related data.
|
|
60
90
|
* @param {RestPlayOptions} options The options to update the player with.
|
|
@@ -65,6 +95,7 @@ class Rest {
|
|
|
65
95
|
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Skipping updatePlayer for guildId: ${options.guildId} - no session ID on node ${this.node.options.identifier}`);
|
|
66
96
|
return null;
|
|
67
97
|
}
|
|
98
|
+
this.assertUpdatePlayerSupported(options);
|
|
68
99
|
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Updating player: ${options.guildId}: ${Utils_1.JSONUtils.safe(options, 2)}`);
|
|
69
100
|
return await this.patch(`/v4/sessions/${this.sessionId}/players/${options.guildId}?noReplace=${options.noReplace ?? false}`, options.data);
|
|
70
101
|
}
|
|
@@ -95,6 +126,184 @@ class Rest {
|
|
|
95
126
|
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Updating session: ${this.sessionId}`);
|
|
96
127
|
return await this.patch(`/v4/sessions/${this.sessionId}`, { resuming, timeout });
|
|
97
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Decodes a single Lavalink track.
|
|
131
|
+
* @param {string} encodedTrack The encoded track string.
|
|
132
|
+
* @returns {Promise<TrackData>} The decoded track.
|
|
133
|
+
*/
|
|
134
|
+
async decodeTrack(encodedTrack) {
|
|
135
|
+
if (typeof encodedTrack !== "string" || encodedTrack.length === 0) {
|
|
136
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
137
|
+
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
|
|
138
|
+
message: "Cannot decode an empty track.",
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return await this.get(`/v4/decodetrack?encodedTrack=${encodeURIComponent(encodedTrack)}`);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Decodes multiple Lavalink tracks.
|
|
145
|
+
* @param {string[]} encodedTracks The encoded track strings.
|
|
146
|
+
* @returns {Promise<TrackData[]>} The decoded tracks.
|
|
147
|
+
*/
|
|
148
|
+
async decodeTracks(encodedTracks) {
|
|
149
|
+
if (!Array.isArray(encodedTracks) || encodedTracks.length === 0) {
|
|
150
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
151
|
+
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
|
|
152
|
+
message: "Cannot decode an empty track list.",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
const result = await this.post("/v4/decodetracks", encodedTracks);
|
|
156
|
+
return Array.isArray(result) ? result : (result?.tracks ?? []);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Retrieves this node's Lavalink info.
|
|
160
|
+
* @returns {Promise<LavalinkInfo>} The node info.
|
|
161
|
+
*/
|
|
162
|
+
async getInfo() {
|
|
163
|
+
return await this.get("/v4/info");
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Retrieves this node's current stats.
|
|
167
|
+
* @returns {Promise<NodeStats>} The node stats.
|
|
168
|
+
*/
|
|
169
|
+
async getStats() {
|
|
170
|
+
const stats = await this.get("/v4/stats");
|
|
171
|
+
if (!stats?.cpu)
|
|
172
|
+
return stats;
|
|
173
|
+
return {
|
|
174
|
+
...stats,
|
|
175
|
+
cpu: {
|
|
176
|
+
...stats.cpu,
|
|
177
|
+
lavalinkLoad: stats.cpu.lavalinkLoad ?? stats.cpu.nodelinkLoad ?? 0,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/** Returns NodeLink connection diagnostics. */
|
|
182
|
+
async getNodeLinkConnection() {
|
|
183
|
+
this.assertNodeLink("get connection diagnostics");
|
|
184
|
+
return await this.get("/v4/connection");
|
|
185
|
+
}
|
|
186
|
+
/** Encodes one track info payload using NodeLink. */
|
|
187
|
+
async encodeNodeLinkTrack(track) {
|
|
188
|
+
this.assertNodeLink("encode a track");
|
|
189
|
+
return await this.get(`/v4/encodetrack?track=${encodeURIComponent(JSON.stringify(track))}`);
|
|
190
|
+
}
|
|
191
|
+
/** Encodes multiple track info payloads using NodeLink. */
|
|
192
|
+
async encodeNodeLinkTracks(tracks) {
|
|
193
|
+
this.assertNodeLink("encode tracks");
|
|
194
|
+
if (!Array.isArray(tracks) || tracks.length === 0) {
|
|
195
|
+
throw new MagmastreamError_1.MagmaStreamError({ code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED, message: "Cannot encode an empty NodeLink track list." });
|
|
196
|
+
}
|
|
197
|
+
return await this.post("/v4/encodedtracks", tracks);
|
|
198
|
+
}
|
|
199
|
+
/** Loads NodeLink meaning/background information for an encoded track. */
|
|
200
|
+
async getNodeLinkMeaning(encodedTrack, language = "en") {
|
|
201
|
+
this.assertNodeLink("load track meaning");
|
|
202
|
+
this.assertEncodedTrack(encodedTrack);
|
|
203
|
+
return await this.get(`/v4/meaning?encodedTrack=${encodeURIComponent(encodedTrack)}&lang=${encodeURIComponent(language)}`);
|
|
204
|
+
}
|
|
205
|
+
/** Resolves NodeLink's direct stream URL and format metadata. */
|
|
206
|
+
async getNodeLinkTrackStream(encodedTrack, itag) {
|
|
207
|
+
this.assertNodeLink("resolve a direct track stream");
|
|
208
|
+
this.assertEncodedTrack(encodedTrack);
|
|
209
|
+
const query = `/v4/trackstream?encodedTrack=${encodeURIComponent(encodedTrack)}${itag === undefined ? "" : `&itag=${encodeURIComponent(String(itag))}`}`;
|
|
210
|
+
return await this.get(query);
|
|
211
|
+
}
|
|
212
|
+
/** Opens NodeLink's raw PCM stream response. The caller consumes response.body. */
|
|
213
|
+
async loadNodeLinkPcmStream(encodedTrack, options = {}) {
|
|
214
|
+
this.assertNodeLink("load a raw PCM stream");
|
|
215
|
+
this.assertEncodedTrack(encodedTrack);
|
|
216
|
+
const controller = new AbortController();
|
|
217
|
+
const timeout = setTimeout(() => controller.abort(), this.node.options.apiRequestTimeoutMs);
|
|
218
|
+
let response;
|
|
219
|
+
try {
|
|
220
|
+
response = await (0, undici_1.fetch)(`${this.url}/v4/loadstream`, {
|
|
221
|
+
method: "POST",
|
|
222
|
+
headers: { "Content-Type": "application/json", Authorization: this.password },
|
|
223
|
+
body: JSON.stringify({ encodedTrack, volume: options.volume ?? 100, position: options.position ?? 0, filters: options.filters ?? {} }),
|
|
224
|
+
signal: controller.signal,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
clearTimeout(timeout);
|
|
229
|
+
}
|
|
230
|
+
if (response.status >= 200 && response.status < 300)
|
|
231
|
+
return response;
|
|
232
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
233
|
+
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
|
|
234
|
+
message: `Request to node ${this.node.options.identifier} failed (${response.status}): ${response.statusText}`,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Retrieves the route planner status.
|
|
239
|
+
* @returns {Promise<RoutePlannerStatus>} The route planner status.
|
|
240
|
+
*/
|
|
241
|
+
async getRoutePlannerStatus() {
|
|
242
|
+
return await this.get("/v4/routeplanner/status");
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Unmarks a failed route planner address.
|
|
246
|
+
* @param {string} address The address to free.
|
|
247
|
+
* @returns {Promise<void>} Void.
|
|
248
|
+
*/
|
|
249
|
+
async freeRoutePlannerAddress(address) {
|
|
250
|
+
if (typeof address !== "string" || address.length === 0) {
|
|
251
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
252
|
+
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
|
|
253
|
+
message: "Cannot free an empty route planner address.",
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
await this.post("/v4/routeplanner/free/address", { address });
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Unmarks all failed route planner addresses.
|
|
260
|
+
* @returns {Promise<void>} Void.
|
|
261
|
+
*/
|
|
262
|
+
async freeAllRoutePlannerAddresses() {
|
|
263
|
+
await this.post("/v4/routeplanner/free/all");
|
|
264
|
+
}
|
|
265
|
+
assertUpdatePlayerSupported(options) {
|
|
266
|
+
if (this.node.isNodeLink)
|
|
267
|
+
return;
|
|
268
|
+
const nodeLinkOnlyFields = [];
|
|
269
|
+
const data = options.data;
|
|
270
|
+
if (data.nextTrack !== undefined)
|
|
271
|
+
nodeLinkOnlyFields.push("nextTrack");
|
|
272
|
+
if (data.loudnessNormalizer !== undefined)
|
|
273
|
+
nodeLinkOnlyFields.push("loudnessNormalizer");
|
|
274
|
+
if (data.fading !== undefined)
|
|
275
|
+
nodeLinkOnlyFields.push("fading");
|
|
276
|
+
if (data.track?.audioTrackId !== undefined)
|
|
277
|
+
nodeLinkOnlyFields.push("track.audioTrackId");
|
|
278
|
+
if (data.track?.language !== undefined)
|
|
279
|
+
nodeLinkOnlyFields.push("track.language");
|
|
280
|
+
const filters = data.filters;
|
|
281
|
+
for (const filterName of ["lowpass", "highpass", "echo", "reverb", "chorus", "compressor", "flanger", "phaser", "phonograph", "spatial", "tape"]) {
|
|
282
|
+
if (filters?.[filterName] !== undefined)
|
|
283
|
+
nodeLinkOnlyFields.push(`filters.${filterName}`);
|
|
284
|
+
}
|
|
285
|
+
if (!nodeLinkOnlyFields.length)
|
|
286
|
+
return;
|
|
287
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
288
|
+
code: Enums_1.MagmaStreamErrorCode.NODE_PROTOCOL_ERROR,
|
|
289
|
+
message: `NodeLink-only update fields cannot be sent to Lavalink node "${this.node.options.identifier}": ${nodeLinkOnlyFields.join(", ")}.`,
|
|
290
|
+
context: { identifier: this.node.options.identifier, fields: nodeLinkOnlyFields, guildId: options.guildId },
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
assertNodeLink(action) {
|
|
294
|
+
if (this.node.isNodeLink)
|
|
295
|
+
return;
|
|
296
|
+
throw new MagmastreamError_1.MagmaStreamError({
|
|
297
|
+
code: Enums_1.MagmaStreamErrorCode.NODE_PROTOCOL_ERROR,
|
|
298
|
+
message: `NodeLink is required to ${action} on node "${this.node.options.identifier}".`,
|
|
299
|
+
context: { identifier: this.node.options.identifier },
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
assertEncodedTrack(encodedTrack) {
|
|
303
|
+
if (typeof encodedTrack === "string" && encodedTrack.length > 0)
|
|
304
|
+
return;
|
|
305
|
+
throw new MagmastreamError_1.MagmaStreamError({ code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED, message: "Encoded track must be a non-empty string." });
|
|
306
|
+
}
|
|
98
307
|
/**
|
|
99
308
|
* Sends a request to the specified endpoint and returns the response data.
|
|
100
309
|
* @param {string} method The HTTP method to use for the request.
|
|
@@ -132,7 +341,7 @@ class Rest {
|
|
|
132
341
|
return data;
|
|
133
342
|
}
|
|
134
343
|
if (status === 404) {
|
|
135
|
-
if (data?.message === "Guild not found") {
|
|
344
|
+
if (data?.message === "Guild not found" || data?.message === "Player not found") {
|
|
136
345
|
return [];
|
|
137
346
|
}
|
|
138
347
|
if (data?.message === "Session not found") {
|