linkdave 0.1.6-dev.87f1a64 → 0.1.6-dev.974add6
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/client.js +19 -2
- package/dist/filters.d.ts +61 -0
- package/dist/filters.js +108 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/node.js +2 -0
- package/dist/player.d.ts +5 -1
- package/dist/player.js +30 -14
- package/dist/queue.d.ts +8 -4
- package/dist/queue.js +5 -5
- package/dist/types.d.ts +32 -2
- package/dist/types.js +22 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -2,8 +2,9 @@ import { GatewayDispatchEvents } from "discord-api-types/v10";
|
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
import { Node } from "./node.js";
|
|
4
4
|
import { Player } from "./player.js";
|
|
5
|
-
import { EventName, ManagerEventName } from "./types.js";
|
|
5
|
+
import { DisconnectReason, EventName, ManagerEventName } from "./types.js";
|
|
6
6
|
const CLIENT_ID_REGEX = /^\d{15,21}$/;
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
7
8
|
export class LinkDaveClient extends EventEmitter {
|
|
8
9
|
#clientId;
|
|
9
10
|
#sendToShard;
|
|
@@ -172,10 +173,26 @@ export class LinkDaveClient extends EventEmitter {
|
|
|
172
173
|
const player = this.#players.get(data.guild_id);
|
|
173
174
|
if (player?.node !== node)
|
|
174
175
|
return;
|
|
176
|
+
if (data.reason === DisconnectReason.ConnectionLost) {
|
|
177
|
+
this.#handleConnectionLost(player);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
175
180
|
player._onVoiceDisconnect();
|
|
176
|
-
this.emit(EventName.VoiceDisconnect, data);
|
|
177
181
|
player.node.decrementPlayerCount();
|
|
178
182
|
this.#players.delete(data.guild_id);
|
|
183
|
+
this.emit(EventName.VoiceDisconnect, data);
|
|
184
|
+
}
|
|
185
|
+
#handleConnectionLost(player) {
|
|
186
|
+
if (player.voiceChannelId)
|
|
187
|
+
player.disconnect();
|
|
188
|
+
else
|
|
189
|
+
player._onVoiceDisconnect();
|
|
190
|
+
player.node.decrementPlayerCount();
|
|
191
|
+
this.#players.delete(player.guildId);
|
|
192
|
+
this.emit(EventName.VoiceDisconnect, {
|
|
193
|
+
guild_id: player.guildId,
|
|
194
|
+
reason: DisconnectReason.ConnectionLost
|
|
195
|
+
});
|
|
179
196
|
}
|
|
180
197
|
_onPlayerDestroy(guildId) {
|
|
181
198
|
const player = this.#players.get(guildId);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Filter, FiltersPayload } from "./types.js";
|
|
2
|
+
export declare class PlayerFilters {
|
|
3
|
+
#private;
|
|
4
|
+
/**
|
|
5
|
+
* Pitch multiplier applied on top of any preset pitch.
|
|
6
|
+
*
|
|
7
|
+
* - **Default:** `0` (no override — preset value is used as-is)
|
|
8
|
+
* - **Normal playback:** `1.0`
|
|
9
|
+
* - **Recommended range:** `0.5` – `2.0`
|
|
10
|
+
* - Values below `0` are clamped to `0`. Values above `2.0` will work
|
|
11
|
+
* but progressively degrade audio quality due to resampling artifacts.
|
|
12
|
+
*
|
|
13
|
+
* When a preset like {@link Filter.Nightcore} is active (which sets pitch
|
|
14
|
+
* to `1.3×`), this value is **multiplied** on top: e.g. `pitch = 0.5`
|
|
15
|
+
* with Nightcore → effective pitch = `1.3 × 0.5 = 0.65`.
|
|
16
|
+
*/
|
|
17
|
+
get pitch(): number;
|
|
18
|
+
set pitch(value: number);
|
|
19
|
+
/**
|
|
20
|
+
* Speed multiplier applied on top of any preset speed.
|
|
21
|
+
*
|
|
22
|
+
* - **Default:** `0` (no override — preset value is used as-is)
|
|
23
|
+
* - **Normal playback:** `1.0`
|
|
24
|
+
* - **Recommended range:** `0.25` – `3.0`
|
|
25
|
+
* - Values below `0` are clamped to `0`. Extreme values (e.g. `>5.0`)
|
|
26
|
+
* will work but may cause audible quality loss since more source
|
|
27
|
+
* samples are consumed per output frame.
|
|
28
|
+
*
|
|
29
|
+
* When a preset like {@link Filter.Vaporwave} is active (which sets speed
|
|
30
|
+
* to `0.8×`), this value is **multiplied** on top: e.g. `speed = 1.25`
|
|
31
|
+
* with Vaporwave → effective speed = `0.8 × 1.25 = 1.0`.
|
|
32
|
+
*/
|
|
33
|
+
get speed(): number;
|
|
34
|
+
set speed(value: number);
|
|
35
|
+
/**
|
|
36
|
+
* Toggle a filter on or off. If `enabled` is omitted the filter is
|
|
37
|
+
* flipped from its current state.
|
|
38
|
+
*
|
|
39
|
+
* **Preset filters** ({@link Filter.Nightcore}, {@link Filter.Vaporwave})
|
|
40
|
+
* adjust both speed and pitch by fixed amounts (1.3× and 0.8×
|
|
41
|
+
* respectively). Enabling both simultaneously multiplies their effects
|
|
42
|
+
* together (effective speed = `1.3 × 0.8 = 1.04`).
|
|
43
|
+
*
|
|
44
|
+
* **DSP filters** ({@link Filter.Tremolo}, {@link Filter.Vibrato},
|
|
45
|
+
* {@link Filter.Rotation}, {@link Filter.LowPass}) modify the audio
|
|
46
|
+
* signal in-place and can all be enabled simultaneously — they are
|
|
47
|
+
* applied in sequence (tremolo → vibrato → rotation → lowpass).
|
|
48
|
+
*/
|
|
49
|
+
toggle(filter: Filter, enabled?: boolean): this;
|
|
50
|
+
/**
|
|
51
|
+
* @returns `true` if any filter is active or if pitch or speed are non-zero.
|
|
52
|
+
*/
|
|
53
|
+
get active(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* @returns an array of all active filters.
|
|
56
|
+
*/
|
|
57
|
+
get activeFilters(): Filter[];
|
|
58
|
+
get(filter: Filter): boolean | undefined;
|
|
59
|
+
clear(): void;
|
|
60
|
+
toPayload(): FiltersPayload | undefined;
|
|
61
|
+
}
|
package/dist/filters.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export class PlayerFilters {
|
|
2
|
+
#state = new Map();
|
|
3
|
+
#pitch = 0;
|
|
4
|
+
#speed = 0;
|
|
5
|
+
/**
|
|
6
|
+
* Pitch multiplier applied on top of any preset pitch.
|
|
7
|
+
*
|
|
8
|
+
* - **Default:** `0` (no override — preset value is used as-is)
|
|
9
|
+
* - **Normal playback:** `1.0`
|
|
10
|
+
* - **Recommended range:** `0.5` – `2.0`
|
|
11
|
+
* - Values below `0` are clamped to `0`. Values above `2.0` will work
|
|
12
|
+
* but progressively degrade audio quality due to resampling artifacts.
|
|
13
|
+
*
|
|
14
|
+
* When a preset like {@link Filter.Nightcore} is active (which sets pitch
|
|
15
|
+
* to `1.3×`), this value is **multiplied** on top: e.g. `pitch = 0.5`
|
|
16
|
+
* with Nightcore → effective pitch = `1.3 × 0.5 = 0.65`.
|
|
17
|
+
*/
|
|
18
|
+
get pitch() {
|
|
19
|
+
return this.#pitch;
|
|
20
|
+
}
|
|
21
|
+
set pitch(value) {
|
|
22
|
+
this.#pitch = Math.max(0, value);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Speed multiplier applied on top of any preset speed.
|
|
26
|
+
*
|
|
27
|
+
* - **Default:** `0` (no override — preset value is used as-is)
|
|
28
|
+
* - **Normal playback:** `1.0`
|
|
29
|
+
* - **Recommended range:** `0.25` – `3.0`
|
|
30
|
+
* - Values below `0` are clamped to `0`. Extreme values (e.g. `>5.0`)
|
|
31
|
+
* will work but may cause audible quality loss since more source
|
|
32
|
+
* samples are consumed per output frame.
|
|
33
|
+
*
|
|
34
|
+
* When a preset like {@link Filter.Vaporwave} is active (which sets speed
|
|
35
|
+
* to `0.8×`), this value is **multiplied** on top: e.g. `speed = 1.25`
|
|
36
|
+
* with Vaporwave → effective speed = `0.8 × 1.25 = 1.0`.
|
|
37
|
+
*/
|
|
38
|
+
get speed() {
|
|
39
|
+
return this.#speed;
|
|
40
|
+
}
|
|
41
|
+
set speed(value) {
|
|
42
|
+
this.#speed = Math.max(0, value);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Toggle a filter on or off. If `enabled` is omitted the filter is
|
|
46
|
+
* flipped from its current state.
|
|
47
|
+
*
|
|
48
|
+
* **Preset filters** ({@link Filter.Nightcore}, {@link Filter.Vaporwave})
|
|
49
|
+
* adjust both speed and pitch by fixed amounts (1.3× and 0.8×
|
|
50
|
+
* respectively). Enabling both simultaneously multiplies their effects
|
|
51
|
+
* together (effective speed = `1.3 × 0.8 = 1.04`).
|
|
52
|
+
*
|
|
53
|
+
* **DSP filters** ({@link Filter.Tremolo}, {@link Filter.Vibrato},
|
|
54
|
+
* {@link Filter.Rotation}, {@link Filter.LowPass}) modify the audio
|
|
55
|
+
* signal in-place and can all be enabled simultaneously — they are
|
|
56
|
+
* applied in sequence (tremolo → vibrato → rotation → lowpass).
|
|
57
|
+
*/
|
|
58
|
+
toggle(filter, enabled) {
|
|
59
|
+
const next = enabled ?? !this.#state.get(filter);
|
|
60
|
+
this.#state.set(filter, next);
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* @returns `true` if any filter is active or if pitch or speed are non-zero.
|
|
65
|
+
*/
|
|
66
|
+
get active() {
|
|
67
|
+
for (const v of this.#state.values()) {
|
|
68
|
+
if (v)
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return this.#pitch > 0 || this.#speed > 0;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* @returns an array of all active filters.
|
|
75
|
+
*/
|
|
76
|
+
get activeFilters() {
|
|
77
|
+
const result = [];
|
|
78
|
+
for (const [k, v] of this.#state)
|
|
79
|
+
if (v)
|
|
80
|
+
result.push(k);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
get(filter) {
|
|
84
|
+
return this.#state.get(filter);
|
|
85
|
+
}
|
|
86
|
+
clear() {
|
|
87
|
+
this.#state.clear();
|
|
88
|
+
this.#pitch = 0;
|
|
89
|
+
this.#speed = 0;
|
|
90
|
+
}
|
|
91
|
+
toPayload() {
|
|
92
|
+
if (!this.active)
|
|
93
|
+
return undefined;
|
|
94
|
+
const enabled = [];
|
|
95
|
+
for (const [k, v] of this.#state) {
|
|
96
|
+
if (v)
|
|
97
|
+
enabled.push(k);
|
|
98
|
+
}
|
|
99
|
+
const payload = {};
|
|
100
|
+
if (enabled.length > 0)
|
|
101
|
+
payload.enabled = enabled;
|
|
102
|
+
if (this.#pitch > 0)
|
|
103
|
+
payload.pitch = this.#pitch;
|
|
104
|
+
if (this.#speed > 0)
|
|
105
|
+
payload.speed = this.#speed;
|
|
106
|
+
return payload;
|
|
107
|
+
}
|
|
108
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/node.js
CHANGED
|
@@ -9,6 +9,7 @@ export var NodeState;
|
|
|
9
9
|
NodeState[NodeState["Connected"] = 2] = "Connected";
|
|
10
10
|
NodeState[NodeState["Draining"] = 3] = "Draining";
|
|
11
11
|
})(NodeState || (NodeState = {}));
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
12
13
|
export class Node extends EventEmitter {
|
|
13
14
|
static NODE_PING_INTERVAL = 30_000;
|
|
14
15
|
name;
|
|
@@ -106,6 +107,7 @@ export class Node extends EventEmitter {
|
|
|
106
107
|
this.#handleMessage(message);
|
|
107
108
|
}
|
|
108
109
|
catch {
|
|
110
|
+
// Invalid messages are silently ignored
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
#handleMessage(message) {
|
package/dist/player.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { type GatewayVoiceServerUpdateDispatchData, type GatewayVoiceStateUpdateDispatchData } from "discord-api-types/v10";
|
|
2
2
|
import type { LinkDaveClient } from "./client.js";
|
|
3
|
+
import { PlayerFilters } from "./filters.js";
|
|
3
4
|
import type { Node } from "./node.js";
|
|
4
5
|
import { Queue } from "./queue.js";
|
|
5
|
-
import type { MigrateReadyPayload, PlayerUpdatePayload, TrackEndPayload, TrackInfo, TrackStartPayload, VoiceConnectPayload } from "./types.js";
|
|
6
|
+
import type { FiltersPayload, MigrateReadyPayload, PlayerUpdatePayload, TrackEndPayload, TrackInfo, TrackStartPayload, VoiceConnectPayload } from "./types.js";
|
|
6
7
|
import { PlayerState } from "./types.js";
|
|
7
8
|
export interface PlayOptions {
|
|
8
9
|
startTime?: number;
|
|
9
10
|
volume?: number;
|
|
11
|
+
requesterId?: string;
|
|
12
|
+
filters?: FiltersPayload;
|
|
10
13
|
}
|
|
11
14
|
export interface PlayerOptions {
|
|
12
15
|
voiceChannelId?: string;
|
|
@@ -30,6 +33,7 @@ export declare class Player {
|
|
|
30
33
|
get playing(): boolean;
|
|
31
34
|
get paused(): boolean;
|
|
32
35
|
get connected(): boolean;
|
|
36
|
+
get filters(): PlayerFilters;
|
|
33
37
|
connect(channelId?: string, timeoutMs?: number): Promise<VoiceConnectPayload>;
|
|
34
38
|
disconnect(): void;
|
|
35
39
|
handleVoiceStateUpdate(data: RawVoiceStateUpdate): Promise<void>;
|
package/dist/player.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { GatewayOpcodes } from "discord-api-types/v10";
|
|
2
|
+
import { PlayerFilters } from "./filters.js";
|
|
2
3
|
import { Queue } from "./queue.js";
|
|
3
|
-
import { EventName, PlayerState, TrackEndReason } from "./types.js";
|
|
4
|
+
import { DisconnectReason, EventName, PlayerState, TrackEndReason } from "./types.js";
|
|
4
5
|
import { unwrap } from "./utils.js";
|
|
5
6
|
export class Player {
|
|
6
7
|
static CONNECT_TIMEOUT = 10_000;
|
|
7
8
|
#client;
|
|
8
9
|
#guildId;
|
|
9
10
|
#queue;
|
|
11
|
+
#filters = new PlayerFilters();
|
|
10
12
|
#node;
|
|
11
13
|
#voiceChannelId = null;
|
|
12
14
|
#selfMute;
|
|
@@ -61,12 +63,16 @@ export class Player {
|
|
|
61
63
|
get connected() {
|
|
62
64
|
return this.#voiceState !== null;
|
|
63
65
|
}
|
|
66
|
+
get filters() {
|
|
67
|
+
return this.#filters;
|
|
68
|
+
}
|
|
64
69
|
connect(channelId, timeoutMs = Player.CONNECT_TIMEOUT) {
|
|
65
70
|
const targetChannel = channelId ?? this.#voiceChannelId;
|
|
66
71
|
if (!targetChannel) {
|
|
67
72
|
throw new RangeError("No voice channel ID provided");
|
|
68
73
|
}
|
|
69
74
|
this.#voiceChannelId = targetChannel;
|
|
75
|
+
this.#state = PlayerState.Connecting;
|
|
70
76
|
this.#client._sendToShard(this.#guildId, {
|
|
71
77
|
op: GatewayOpcodes.VoiceStateUpdate,
|
|
72
78
|
d: {
|
|
@@ -78,6 +84,9 @@ export class Player {
|
|
|
78
84
|
});
|
|
79
85
|
return new Promise((resolve, reject) => {
|
|
80
86
|
const cleanup = () => {
|
|
87
|
+
if (this.#state === PlayerState.Connecting) {
|
|
88
|
+
this.#state = PlayerState.Idle;
|
|
89
|
+
}
|
|
81
90
|
this.#node.off(EventName.VoiceConnect, onConnect);
|
|
82
91
|
this.#node.off(EventName.VoiceDisconnect, onDisconnect);
|
|
83
92
|
clearTimeout(timer);
|
|
@@ -96,6 +105,8 @@ export class Player {
|
|
|
96
105
|
const onDisconnect = (event) => {
|
|
97
106
|
if (event.guild_id !== this.#guildId)
|
|
98
107
|
return;
|
|
108
|
+
if (event.reason === DisconnectReason.Requested)
|
|
109
|
+
return;
|
|
99
110
|
cleanup();
|
|
100
111
|
reject(new Error(`Voice connection failed for guild "${this.#guildId}": ${event.reason ?? "unknown"}`));
|
|
101
112
|
};
|
|
@@ -117,8 +128,9 @@ export class Player {
|
|
|
117
128
|
}
|
|
118
129
|
async handleVoiceStateUpdate(data) {
|
|
119
130
|
if (!data.channel_id) {
|
|
131
|
+
const hadVoiceState = this.#voiceState !== null;
|
|
120
132
|
this.#cleanup();
|
|
121
|
-
if (this.#node.connected) {
|
|
133
|
+
if (hadVoiceState && this.#node.connected) {
|
|
122
134
|
const [, err] = await unwrap(this.#node.sendDisconnect(this.#guildId));
|
|
123
135
|
if (err)
|
|
124
136
|
this.#node.emit(EventName.Error, err);
|
|
@@ -144,7 +156,7 @@ export class Player {
|
|
|
144
156
|
this.#pendingVoice ??= {};
|
|
145
157
|
const endpoint = data.endpoint || this.#pendingVoice.serverEvent?.endpoint;
|
|
146
158
|
if (!endpoint)
|
|
147
|
-
throw new Error("Missing voice server endpoint");
|
|
159
|
+
throw new Error("Missing voice server endpoint"); // TODO
|
|
148
160
|
this.#pendingVoice.serverEvent = {
|
|
149
161
|
token: data.token,
|
|
150
162
|
guild_id: data.guild_id,
|
|
@@ -177,10 +189,13 @@ export class Player {
|
|
|
177
189
|
await this.#sendPlay(url, options);
|
|
178
190
|
}
|
|
179
191
|
async #sendPlay(url, options = {}) {
|
|
192
|
+
const filters = options.filters ?? this.#filters.toPayload();
|
|
180
193
|
await this.#node.sendPlay(this.#guildId, {
|
|
181
194
|
url,
|
|
182
195
|
...(options.startTime !== undefined && { start_time: options.startTime }),
|
|
183
|
-
...(options.volume !== undefined && { volume: options.volume })
|
|
196
|
+
...(options.volume !== undefined && { volume: options.volume }),
|
|
197
|
+
...(options.requesterId !== undefined && { requester_id: options.requesterId }),
|
|
198
|
+
...(filters !== undefined && { filters })
|
|
184
199
|
});
|
|
185
200
|
}
|
|
186
201
|
async pause() {
|
|
@@ -211,9 +226,8 @@ export class Player {
|
|
|
211
226
|
}
|
|
212
227
|
const waitForVoiceDisconnect = this.#waitForNodeVoiceDisconnect(Player.CONNECT_TIMEOUT);
|
|
213
228
|
await unwrap(this.#node.sendDisconnect(this.#guildId));
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
229
|
+
await waitForVoiceDisconnect;
|
|
230
|
+
this.#client._onPlayerDestroy(this.#guildId);
|
|
217
231
|
}
|
|
218
232
|
#waitForNodeVoiceDisconnect(timeoutMs) {
|
|
219
233
|
return new Promise((resolve) => {
|
|
@@ -259,7 +273,7 @@ export class Player {
|
|
|
259
273
|
this.#current = null;
|
|
260
274
|
this.#state = PlayerState.Idle;
|
|
261
275
|
}
|
|
262
|
-
this.#queue._onTrackEnd(data.reason !== TrackEndReason.Stopped);
|
|
276
|
+
this.#queue._onTrackEnd(data.reason !== TrackEndReason.Stopped && data.reason !== TrackEndReason.Replaced);
|
|
263
277
|
}
|
|
264
278
|
#cleanup() {
|
|
265
279
|
this.#voiceChannelId = null;
|
|
@@ -279,6 +293,7 @@ export class Player {
|
|
|
279
293
|
}
|
|
280
294
|
const targetNode = this.#migrationTarget;
|
|
281
295
|
const oldNode = this.#node;
|
|
296
|
+
// Don't send disconnect to old node - we're migrating
|
|
282
297
|
this.#client._updatePlayerNode(this.#guildId, oldNode, targetNode);
|
|
283
298
|
this.#node = targetNode;
|
|
284
299
|
if (this.#voiceState) {
|
|
@@ -291,16 +306,17 @@ export class Player {
|
|
|
291
306
|
});
|
|
292
307
|
}
|
|
293
308
|
if (data.state === PlayerState.Playing && data.url) {
|
|
294
|
-
const playData = {
|
|
295
|
-
url: data.url,
|
|
296
|
-
start_time: data.position,
|
|
297
|
-
volume: data.volume
|
|
298
|
-
};
|
|
299
309
|
const onVoiceConnect = (event) => {
|
|
300
310
|
if (event.guild_id !== this.#guildId)
|
|
301
311
|
return;
|
|
302
312
|
this.#node.off(EventName.VoiceConnect, onVoiceConnect);
|
|
303
|
-
void this.#node.sendPlay(this.#guildId,
|
|
313
|
+
void this.#node.sendPlay(this.#guildId, {
|
|
314
|
+
url: data.url,
|
|
315
|
+
start_time: data.position,
|
|
316
|
+
volume: data.volume,
|
|
317
|
+
...(data.requester_id !== undefined && { requester_id: data.requester_id }),
|
|
318
|
+
...(data.filters !== undefined && { filters: data.filters })
|
|
319
|
+
});
|
|
304
320
|
};
|
|
305
321
|
this.#node.on(EventName.VoiceConnect, onVoiceConnect);
|
|
306
322
|
}
|
package/dist/queue.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import type { Player } from "./player.js";
|
|
1
|
+
import type { Player, PlayOptions } from "./player.js";
|
|
2
|
+
export interface QueueItem {
|
|
3
|
+
uri: string;
|
|
4
|
+
options: PlayOptions;
|
|
5
|
+
}
|
|
2
6
|
export declare class Queue {
|
|
3
7
|
#private;
|
|
4
8
|
constructor(player: Player);
|
|
5
|
-
add(uri: string): this;
|
|
9
|
+
add(uri: string, options?: PlayOptions): this;
|
|
6
10
|
start(): Promise<void>;
|
|
7
11
|
skip(): Promise<void>;
|
|
8
|
-
remove(index: number):
|
|
12
|
+
remove(index: number): QueueItem | undefined;
|
|
9
13
|
clear(): void;
|
|
10
|
-
get tracks(): readonly
|
|
14
|
+
get tracks(): readonly QueueItem[];
|
|
11
15
|
get size(): number;
|
|
12
16
|
get active(): boolean;
|
|
13
17
|
_onTrackEnd(finished: boolean): void;
|
package/dist/queue.js
CHANGED
|
@@ -6,8 +6,8 @@ export class Queue {
|
|
|
6
6
|
constructor(player) {
|
|
7
7
|
this.#player = player;
|
|
8
8
|
}
|
|
9
|
-
add(uri) {
|
|
10
|
-
this.#tracks.push(uri);
|
|
9
|
+
add(uri, options = {}) {
|
|
10
|
+
this.#tracks.push({ uri, options });
|
|
11
11
|
return this;
|
|
12
12
|
}
|
|
13
13
|
async start() {
|
|
@@ -56,10 +56,10 @@ export class Queue {
|
|
|
56
56
|
if (!item)
|
|
57
57
|
return;
|
|
58
58
|
this.#player
|
|
59
|
-
.play(item,
|
|
59
|
+
.play(item.uri, item.options, true)
|
|
60
60
|
.then(() => null, (error_) => {
|
|
61
61
|
const error = error_ instanceof Error ? error_ : new Error(String(error_));
|
|
62
|
-
const payload = { guild_id: this.#player.guildId, url: item, error };
|
|
62
|
+
const payload = { guild_id: this.#player.guildId, url: item.uri, error };
|
|
63
63
|
this.#player.node.emit(EventName.QueueError, payload);
|
|
64
64
|
this._onTrackEnd(true);
|
|
65
65
|
});
|
|
@@ -71,6 +71,6 @@ export class Queue {
|
|
|
71
71
|
const item = this.#tracks.shift();
|
|
72
72
|
if (!item)
|
|
73
73
|
return;
|
|
74
|
-
await this.#player.play(item,
|
|
74
|
+
await this.#player.play(item.uri, item.options, true);
|
|
75
75
|
}
|
|
76
76
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -26,7 +26,27 @@ export declare enum TrackEndReason {
|
|
|
26
26
|
export declare enum PlayerState {
|
|
27
27
|
Idle = "idle",
|
|
28
28
|
Playing = "playing",
|
|
29
|
-
Paused = "paused"
|
|
29
|
+
Paused = "paused",
|
|
30
|
+
Connecting = "connecting"
|
|
31
|
+
}
|
|
32
|
+
export declare enum Filter {
|
|
33
|
+
/** Slows and lowers pitch (speed ×0.8, pitch ×0.8). */
|
|
34
|
+
Vaporwave = 0,
|
|
35
|
+
/** Speeds up and raises pitch (speed ×1.3, pitch ×1.3). */
|
|
36
|
+
Nightcore = 1,
|
|
37
|
+
/** Rotates audio around the stereo field at 0.2 Hz. */
|
|
38
|
+
Rotation = 2,
|
|
39
|
+
/** Oscillates volume at 4 Hz with 0.6 depth. */
|
|
40
|
+
Tremolo = 3,
|
|
41
|
+
/** Oscillates pitch at 4 Hz with 0.5 depth. */
|
|
42
|
+
Vibrato = 4,
|
|
43
|
+
/** Suppresses high frequencies (smoothing factor 20). */
|
|
44
|
+
LowPass = 5
|
|
45
|
+
}
|
|
46
|
+
export interface FiltersPayload {
|
|
47
|
+
enabled?: Filter[];
|
|
48
|
+
pitch?: number;
|
|
49
|
+
speed?: number;
|
|
30
50
|
}
|
|
31
51
|
export type ServerMessage = {
|
|
32
52
|
op: ServerOpCodes.Ready;
|
|
@@ -88,6 +108,8 @@ export interface PlayPayload {
|
|
|
88
108
|
url: string;
|
|
89
109
|
start_time?: number;
|
|
90
110
|
volume?: number;
|
|
111
|
+
requester_id?: string;
|
|
112
|
+
filters?: FiltersPayload;
|
|
91
113
|
}
|
|
92
114
|
export interface GuildPayload {
|
|
93
115
|
guild_id: string;
|
|
@@ -112,6 +134,7 @@ export interface TrackInfo {
|
|
|
112
134
|
url: string;
|
|
113
135
|
title?: string;
|
|
114
136
|
duration: number;
|
|
137
|
+
requester_id?: string;
|
|
115
138
|
}
|
|
116
139
|
export interface TrackStartPayload {
|
|
117
140
|
guild_id: string;
|
|
@@ -132,13 +155,18 @@ export interface QueueErrorPayload {
|
|
|
132
155
|
url: string;
|
|
133
156
|
error: Error;
|
|
134
157
|
}
|
|
158
|
+
export declare enum DisconnectReason {
|
|
159
|
+
ConnectionLost = "connection_lost",
|
|
160
|
+
ConnectionFailed = "connection_failed",
|
|
161
|
+
Requested = "requested"
|
|
162
|
+
}
|
|
135
163
|
export interface VoiceConnectPayload {
|
|
136
164
|
guild_id: string;
|
|
137
165
|
channel_id: string;
|
|
138
166
|
}
|
|
139
167
|
export interface VoiceDisconnectPayload {
|
|
140
168
|
guild_id: string;
|
|
141
|
-
reason?:
|
|
169
|
+
reason?: DisconnectReason;
|
|
142
170
|
}
|
|
143
171
|
export interface StatsPayload {
|
|
144
172
|
players: number;
|
|
@@ -160,6 +188,8 @@ export interface MigrateReadyPayload {
|
|
|
160
188
|
position: number;
|
|
161
189
|
volume: number;
|
|
162
190
|
state: PlayerState;
|
|
191
|
+
requester_id?: string;
|
|
192
|
+
filters?: FiltersPayload;
|
|
163
193
|
}
|
|
164
194
|
export interface ClosePayload {
|
|
165
195
|
code: number;
|
package/dist/types.js
CHANGED
|
@@ -30,7 +30,29 @@ export var PlayerState;
|
|
|
30
30
|
PlayerState["Idle"] = "idle";
|
|
31
31
|
PlayerState["Playing"] = "playing";
|
|
32
32
|
PlayerState["Paused"] = "paused";
|
|
33
|
+
PlayerState["Connecting"] = "connecting";
|
|
33
34
|
})(PlayerState || (PlayerState = {}));
|
|
35
|
+
export var Filter;
|
|
36
|
+
(function (Filter) {
|
|
37
|
+
/** Slows and lowers pitch (speed ×0.8, pitch ×0.8). */
|
|
38
|
+
Filter[Filter["Vaporwave"] = 0] = "Vaporwave";
|
|
39
|
+
/** Speeds up and raises pitch (speed ×1.3, pitch ×1.3). */
|
|
40
|
+
Filter[Filter["Nightcore"] = 1] = "Nightcore";
|
|
41
|
+
/** Rotates audio around the stereo field at 0.2 Hz. */
|
|
42
|
+
Filter[Filter["Rotation"] = 2] = "Rotation";
|
|
43
|
+
/** Oscillates volume at 4 Hz with 0.6 depth. */
|
|
44
|
+
Filter[Filter["Tremolo"] = 3] = "Tremolo";
|
|
45
|
+
/** Oscillates pitch at 4 Hz with 0.5 depth. */
|
|
46
|
+
Filter[Filter["Vibrato"] = 4] = "Vibrato";
|
|
47
|
+
/** Suppresses high frequencies (smoothing factor 20). */
|
|
48
|
+
Filter[Filter["LowPass"] = 5] = "LowPass";
|
|
49
|
+
})(Filter || (Filter = {}));
|
|
50
|
+
export var DisconnectReason;
|
|
51
|
+
(function (DisconnectReason) {
|
|
52
|
+
DisconnectReason["ConnectionLost"] = "connection_lost";
|
|
53
|
+
DisconnectReason["ConnectionFailed"] = "connection_failed";
|
|
54
|
+
DisconnectReason["Requested"] = "requested";
|
|
55
|
+
})(DisconnectReason || (DisconnectReason = {}));
|
|
34
56
|
export var EventName;
|
|
35
57
|
(function (EventName) {
|
|
36
58
|
EventName["Ready"] = "ready";
|
package/package.json
CHANGED