shoukaku-bun 4.2.0-b
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/LICENSE +21 -0
- package/README.md +88 -0
- package/index.ts +9 -0
- package/package.json +56 -0
- package/src/Constants.ts +55 -0
- package/src/Shoukaku.ts +295 -0
- package/src/Utils.ts +58 -0
- package/src/connectors/Connector.ts +49 -0
- package/src/connectors/README.md +42 -0
- package/src/connectors/libs/DiscordJS.ts +21 -0
- package/src/connectors/libs/Eris.ts +21 -0
- package/src/connectors/libs/OceanicJS.ts +21 -0
- package/src/connectors/libs/Seyfert.ts +26 -0
- package/src/connectors/libs/index.ts +4 -0
- package/src/guild/Connection.ts +248 -0
- package/src/guild/Player.ts +543 -0
- package/src/node/Node.ts +442 -0
- package/src/node/Rest.ts +433 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { NodeOption } from '../../Shoukaku';
|
|
3
|
+
import { Connector } from '../Connector';
|
|
4
|
+
|
|
5
|
+
export class DiscordJS extends Connector {
|
|
6
|
+
// sendPacket is where your library send packets to Discord Gateway
|
|
7
|
+
public sendPacket(shardId: number, payload: any, important: boolean): void {
|
|
8
|
+
return this.client.ws.shards.get(shardId)?.send(payload, important);
|
|
9
|
+
}
|
|
10
|
+
// getId is a getter where the lib stores the client user (the one logged in as a bot) id
|
|
11
|
+
public getId(): string {
|
|
12
|
+
return this.client.user.id;
|
|
13
|
+
}
|
|
14
|
+
// Listen attaches the event listener to the library you are using
|
|
15
|
+
public listen(nodes: NodeOption[]): void {
|
|
16
|
+
// Only attach to ready event once, refer to your library for its ready event
|
|
17
|
+
this.client.once('clientReady', () => this.ready(nodes));
|
|
18
|
+
// Attach to the raw websocket event, this event must be 1:1 on spec with dapi (most libs implement this)
|
|
19
|
+
this.client.on('raw', (packet: any) => this.raw(packet));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { NodeOption } from '../../Shoukaku';
|
|
3
|
+
import { Connector } from '../Connector';
|
|
4
|
+
|
|
5
|
+
export class Eris extends Connector {
|
|
6
|
+
// sendPacket is where your library send packets to Discord Gateway
|
|
7
|
+
public sendPacket(shardId: number, payload: any, important: boolean): void {
|
|
8
|
+
return this.client.shards.get(shardId)?.sendWS(payload.op, payload.d, important);
|
|
9
|
+
}
|
|
10
|
+
// getId is a getter where the lib stores the client user (the one logged in as a bot) id
|
|
11
|
+
public getId(): string {
|
|
12
|
+
return this.client.user.id;
|
|
13
|
+
}
|
|
14
|
+
// Listen attaches the event listener to the library you are using
|
|
15
|
+
public listen(nodes: NodeOption[]): void {
|
|
16
|
+
// Only attach to ready event once, refer to your library for its ready event
|
|
17
|
+
this.client.once('ready', () => this.ready(nodes));
|
|
18
|
+
// Attach to the raw websocket event, this event must be 1:1 on spec with dapi (most libs implement this)
|
|
19
|
+
this.client.on('rawWS', (packet: any) => this.raw(packet));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { NodeOption } from '../../Shoukaku';
|
|
3
|
+
import { Connector } from '../Connector';
|
|
4
|
+
|
|
5
|
+
export class OceanicJS extends Connector {
|
|
6
|
+
// sendPacket is where your library send packets to Discord Gateway
|
|
7
|
+
public sendPacket(shardId: number, payload: any, important: boolean): void {
|
|
8
|
+
return this.client.shards.get(shardId)?.send(payload.op, payload.d, important);
|
|
9
|
+
}
|
|
10
|
+
// getId is a getter where the lib stores the client user (the one logged in as a bot) id
|
|
11
|
+
public getId(): string {
|
|
12
|
+
return this.client.user.id;
|
|
13
|
+
}
|
|
14
|
+
// Listen attaches the event listener to the library you are using
|
|
15
|
+
public listen(nodes: NodeOption[]): void {
|
|
16
|
+
// Only attach to ready event once, refer to your library for its ready event
|
|
17
|
+
this.client.once('ready', () => this.ready(nodes));
|
|
18
|
+
// Attach to the raw websocket event, this event must be 1:1 on spec with dapi (most libs implement this)
|
|
19
|
+
this.client.on('packet', (packet: any) => this.raw(packet));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { NodeOption } from '../../Shoukaku';
|
|
3
|
+
import { Connector } from '../Connector';
|
|
4
|
+
|
|
5
|
+
export class Seyfert extends Connector {
|
|
6
|
+
// sendPacket is where your library send packets to Discord Gateway
|
|
7
|
+
public sendPacket(shardId: number, payload: unknown, important: boolean): void {
|
|
8
|
+
return this.client.gateway.send(shardId, payload);
|
|
9
|
+
}
|
|
10
|
+
// getId is a getter where the lib stores the client user (the one logged in as a bot) id
|
|
11
|
+
public getId(): string {
|
|
12
|
+
return this.client.botId;
|
|
13
|
+
}
|
|
14
|
+
// Listen attaches the event listener to the library you are using
|
|
15
|
+
public listen(nodes: NodeOption[]): void {
|
|
16
|
+
this.client.events.values.RAW = {
|
|
17
|
+
data: { name: 'raw' },
|
|
18
|
+
run: (packet: any) => {
|
|
19
|
+
// Only attach to ready event once, refer to your library for its ready event
|
|
20
|
+
if (packet.t === 'READY') return this.ready(nodes);
|
|
21
|
+
// Attach to the raw websocket event, this event must be 1:1 on spec with dapi (most libs implement this)
|
|
22
|
+
return this.raw(packet);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { EventEmitter, once } from 'node:events';
|
|
2
|
+
import { State, VoiceState } from '../Constants';
|
|
3
|
+
import type { Shoukaku, VoiceChannelOptions } from '../Shoukaku';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents the partial payload from a stateUpdate event
|
|
7
|
+
*/
|
|
8
|
+
export interface StateUpdatePartial {
|
|
9
|
+
channel_id?: string;
|
|
10
|
+
session_id?: string;
|
|
11
|
+
self_deaf: boolean;
|
|
12
|
+
self_mute: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represents the payload from a serverUpdate event
|
|
17
|
+
*/
|
|
18
|
+
export interface ServerUpdate {
|
|
19
|
+
token: string;
|
|
20
|
+
guild_id: string;
|
|
21
|
+
endpoint: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Represents a connection to a Discord voice channel
|
|
26
|
+
*/
|
|
27
|
+
export class Connection extends EventEmitter {
|
|
28
|
+
/**
|
|
29
|
+
* The manager where this connection is on
|
|
30
|
+
*/
|
|
31
|
+
public manager: Shoukaku;
|
|
32
|
+
/**
|
|
33
|
+
* GuildId of the connection that is being managed by this instance
|
|
34
|
+
*/
|
|
35
|
+
public guildId: string;
|
|
36
|
+
/**
|
|
37
|
+
* VoiceChannelId of the connection that is being managed by this instance
|
|
38
|
+
*/
|
|
39
|
+
public channelId: string | null;
|
|
40
|
+
/**
|
|
41
|
+
* ShardId where this connection sends data on
|
|
42
|
+
*/
|
|
43
|
+
public shardId: number;
|
|
44
|
+
/**
|
|
45
|
+
* Mute status in connected voice channel
|
|
46
|
+
*/
|
|
47
|
+
public muted: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Deafen status in connected voice channel
|
|
50
|
+
*/
|
|
51
|
+
public deafened: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Id of the voice channel where this instance was connected before the current channelId
|
|
54
|
+
*/
|
|
55
|
+
public lastChannelId: string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Id of the currently active voice channel connection
|
|
58
|
+
*/
|
|
59
|
+
public sessionId: string | null;
|
|
60
|
+
/**
|
|
61
|
+
* Region of connected voice channel
|
|
62
|
+
*/
|
|
63
|
+
public region: string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Last region of the connected voice channel
|
|
66
|
+
*/
|
|
67
|
+
public lastRegion: string | null;
|
|
68
|
+
/**
|
|
69
|
+
* Cached serverUpdate event from Lavalink
|
|
70
|
+
*/
|
|
71
|
+
public serverUpdate: ServerUpdate | null;
|
|
72
|
+
/**
|
|
73
|
+
* Connection state
|
|
74
|
+
*/
|
|
75
|
+
public state: State;
|
|
76
|
+
/**
|
|
77
|
+
* @param manager The manager of this connection
|
|
78
|
+
* @param options The options to pass in connection creation
|
|
79
|
+
* @param options.guildId GuildId in which voice channel to connect to is located
|
|
80
|
+
* @param options.shardId ShardId in which the guild exists
|
|
81
|
+
* @param options.channelId ChannelId of voice channel to connect to
|
|
82
|
+
* @param options.deaf Optional boolean value to specify whether to deafen the current bot user
|
|
83
|
+
* @param options.mute Optional boolean value to specify whether to mute the current bot user
|
|
84
|
+
*/
|
|
85
|
+
constructor(manager: Shoukaku, options: VoiceChannelOptions) {
|
|
86
|
+
super();
|
|
87
|
+
this.manager = manager;
|
|
88
|
+
this.guildId = options.guildId;
|
|
89
|
+
this.channelId = options.channelId;
|
|
90
|
+
this.shardId = options.shardId;
|
|
91
|
+
this.muted = options.mute ?? false;
|
|
92
|
+
this.deafened = options.deaf ?? false;
|
|
93
|
+
this.lastChannelId = null;
|
|
94
|
+
this.sessionId = null;
|
|
95
|
+
this.region = null;
|
|
96
|
+
this.lastRegion = null;
|
|
97
|
+
this.serverUpdate = null;
|
|
98
|
+
this.state = State.DISCONNECTED;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Set the deafen status for the current bot user
|
|
103
|
+
* @param deaf Boolean value to indicate whether to deafen or undeafen
|
|
104
|
+
* @defaultValue false
|
|
105
|
+
*/
|
|
106
|
+
public setDeaf(deaf = false): void {
|
|
107
|
+
this.deafened = deaf;
|
|
108
|
+
this.sendVoiceUpdate();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Set the mute status for the current bot user
|
|
113
|
+
* @param mute Boolean value to indicate whether to mute or unmute
|
|
114
|
+
* @defaultValue false
|
|
115
|
+
*/
|
|
116
|
+
public setMute(mute = false): void {
|
|
117
|
+
this.muted = mute;
|
|
118
|
+
this.sendVoiceUpdate();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Disconnect the current bot user from the connected voice channel
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
public disconnect(): void {
|
|
126
|
+
if (this.state === State.DISCONNECTED) return;
|
|
127
|
+
this.channelId = null;
|
|
128
|
+
this.deafened = false;
|
|
129
|
+
this.muted = false;
|
|
130
|
+
this.removeAllListeners();
|
|
131
|
+
this.sendVoiceUpdate();
|
|
132
|
+
this.state = State.DISCONNECTED;
|
|
133
|
+
this.debug(`[Voice] -> [Node] & [Discord] : Connection Destroyed | Guild: ${this.guildId}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Connect the current bot user to a voice channel
|
|
138
|
+
* @internal
|
|
139
|
+
*/
|
|
140
|
+
public async connect(): Promise<void> {
|
|
141
|
+
if (this.state === State.CONNECTING || this.state === State.CONNECTED) return;
|
|
142
|
+
|
|
143
|
+
this.state = State.CONNECTING;
|
|
144
|
+
this.sendVoiceUpdate();
|
|
145
|
+
this.debug(`[Voice] -> [Discord] : Requesting Connection | Guild: ${this.guildId}`);
|
|
146
|
+
|
|
147
|
+
const controller = new AbortController();
|
|
148
|
+
const timeout = setTimeout(() => controller.abort(), this.manager.options.voiceConnectionTimeout * 1000);
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const [ status ] = await once(this, 'connectionUpdate', { signal: controller.signal }) as [ VoiceState ];
|
|
152
|
+
if (status !== VoiceState.SESSION_READY) {
|
|
153
|
+
switch (status) {
|
|
154
|
+
case VoiceState.SESSION_ID_MISSING: throw new Error('The voice connection is not established due to missing session id');
|
|
155
|
+
case VoiceState.SESSION_ENDPOINT_MISSING: throw new Error('The voice connection is not established due to missing connection endpoint');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
this.state = State.CONNECTED;
|
|
159
|
+
} catch (e: unknown) {
|
|
160
|
+
const error = e as Error;
|
|
161
|
+
this.debug(`[Voice] </- [Discord] : Request Connection Failed | Guild: ${this.guildId}`);
|
|
162
|
+
if (error.name === 'AbortError')
|
|
163
|
+
throw new Error(`The voice connection is not established in ${this.manager.options.voiceConnectionTimeout} seconds`);
|
|
164
|
+
throw error;
|
|
165
|
+
} finally {
|
|
166
|
+
clearTimeout(timeout);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Updates SessionId, ChannelId, Deafen and Mute data of this instance
|
|
172
|
+
* @param options
|
|
173
|
+
* @param options.session_id Id of the current session
|
|
174
|
+
* @param options.channel_id Id of the connected voice channel
|
|
175
|
+
* @param options.self_deaf Boolean that indicates if the current bot user is deafened or not
|
|
176
|
+
* @param options.self_mute Boolean that indicates if the current bot user is muted or not
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
public setStateUpdate({ session_id, channel_id, self_deaf, self_mute }: StateUpdatePartial): void {
|
|
180
|
+
this.lastChannelId = this.channelId?.repeat(1) ?? null;
|
|
181
|
+
this.channelId = channel_id ?? null;
|
|
182
|
+
|
|
183
|
+
if (this.channelId && this.lastChannelId !== this.channelId) {
|
|
184
|
+
this.debug(`[Voice] <- [Discord] : Channel Moved | Old Channel: ${this.channelId} Guild: ${this.guildId}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!this.channelId) {
|
|
188
|
+
this.state = State.DISCONNECTED;
|
|
189
|
+
this.debug(`[Voice] <- [Discord] : Channel Disconnected | Guild: ${this.guildId}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.deafened = self_deaf;
|
|
193
|
+
this.muted = self_mute;
|
|
194
|
+
this.sessionId = session_id ?? null;
|
|
195
|
+
this.debug(`[Voice] <- [Discord] : State Update Received | Channel: ${this.channelId} Session ID: ${session_id} Guild: ${this.guildId}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Sets the server update data for this connection
|
|
200
|
+
* @internal
|
|
201
|
+
*/
|
|
202
|
+
public setServerUpdate(data: ServerUpdate): void {
|
|
203
|
+
if (!data.endpoint) {
|
|
204
|
+
this.emit('connectionUpdate', VoiceState.SESSION_ENDPOINT_MISSING);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (!this.sessionId) {
|
|
208
|
+
this.emit('connectionUpdate', VoiceState.SESSION_ID_MISSING);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.lastRegion = this.region?.repeat(1) ?? null;
|
|
213
|
+
this.region = data.endpoint.split('.').shift()?.replace(/[0-9]/g, '') ?? null;
|
|
214
|
+
|
|
215
|
+
if (this.region && this.lastRegion !== this.region) {
|
|
216
|
+
this.debug(`[Voice] <- [Discord] : Voice Region Moved | Old Region: ${this.lastRegion} New Region: ${this.region} Guild: ${this.guildId}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.serverUpdate = data;
|
|
220
|
+
this.emit('connectionUpdate', VoiceState.SESSION_READY);
|
|
221
|
+
this.debug(`[Voice] <- [Discord] : Server Update Received | Server: ${this.region} Guild: ${this.guildId}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Send voice data to discord
|
|
226
|
+
* @internal
|
|
227
|
+
*/
|
|
228
|
+
private sendVoiceUpdate() {
|
|
229
|
+
this.send({ guild_id: this.guildId, channel_id: this.channelId, self_deaf: this.deafened, self_mute: this.muted });
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Send data to Discord
|
|
234
|
+
* @param data The data to send
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
private send(data: unknown): void {
|
|
238
|
+
this.manager.connector.sendPacket(this.shardId, { op: 4, d: data }, false);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Emits a debug log
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
private debug(message: string): void {
|
|
246
|
+
this.manager.emit('debug', this.constructor.name, message);
|
|
247
|
+
}
|
|
248
|
+
}
|