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,543 @@
|
|
|
1
|
+
import { OpCodes, State } from '../Constants';
|
|
2
|
+
import type { Node } from '../node/Node';
|
|
3
|
+
import type { Exception, Track, UpdatePlayerInfo, UpdatePlayerOptions } from '../node/Rest';
|
|
4
|
+
import { TypedEventEmitter } from '../Utils';
|
|
5
|
+
import { Connection } from './Connection';
|
|
6
|
+
|
|
7
|
+
export type TrackEndReason = 'finished' | 'loadFailed' | 'stopped' | 'replaced' | 'cleanup';
|
|
8
|
+
export type PlayOptions = Omit<UpdatePlayerOptions, 'filters' | 'voice'>;
|
|
9
|
+
export type ResumeOptions = Omit<UpdatePlayerOptions, 'track' | 'filters' | 'voice'>;
|
|
10
|
+
|
|
11
|
+
export enum PlayerEventType {
|
|
12
|
+
TRACK_START_EVENT = 'TrackStartEvent',
|
|
13
|
+
TRACK_END_EVENT = 'TrackEndEvent',
|
|
14
|
+
TRACK_EXCEPTION_EVENT = 'TrackExceptionEvent',
|
|
15
|
+
TRACK_STUCK_EVENT = 'TrackStuckEvent',
|
|
16
|
+
WEBSOCKET_CLOSED_EVENT = 'WebSocketClosedEvent'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Band {
|
|
20
|
+
band: number;
|
|
21
|
+
gain: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface KaraokeSettings {
|
|
25
|
+
level?: number;
|
|
26
|
+
monoLevel?: number;
|
|
27
|
+
filterBand?: number;
|
|
28
|
+
filterWidth?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TimescaleSettings {
|
|
32
|
+
speed?: number;
|
|
33
|
+
pitch?: number;
|
|
34
|
+
rate?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface FreqSettings {
|
|
38
|
+
frequency?: number;
|
|
39
|
+
depth?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface RotationSettings {
|
|
43
|
+
rotationHz?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface DistortionSettings {
|
|
47
|
+
sinOffset?: number;
|
|
48
|
+
sinScale?: number;
|
|
49
|
+
cosOffset?: number;
|
|
50
|
+
cosScale?: number;
|
|
51
|
+
tanOffset?: number;
|
|
52
|
+
tanScale?: number;
|
|
53
|
+
offset?: number;
|
|
54
|
+
scale?: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ChannelMixSettings {
|
|
58
|
+
leftToLeft?: number;
|
|
59
|
+
leftToRight?: number;
|
|
60
|
+
rightToLeft?: number;
|
|
61
|
+
rightToRight?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface LowPassSettings {
|
|
65
|
+
smoothing?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PlayerEvent {
|
|
69
|
+
op: OpCodes.EVENT;
|
|
70
|
+
guildId: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface TrackStartEvent extends PlayerEvent {
|
|
74
|
+
type: PlayerEventType.TRACK_START_EVENT;
|
|
75
|
+
track: Track;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface TrackEndEvent extends PlayerEvent {
|
|
79
|
+
type: PlayerEventType.TRACK_END_EVENT;
|
|
80
|
+
track: Track;
|
|
81
|
+
reason: TrackEndReason;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface TrackStuckEvent extends PlayerEvent {
|
|
85
|
+
type: PlayerEventType.TRACK_STUCK_EVENT;
|
|
86
|
+
track: Track;
|
|
87
|
+
thresholdMs: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface TrackExceptionEvent extends PlayerEvent {
|
|
91
|
+
type: PlayerEventType.TRACK_EXCEPTION_EVENT;
|
|
92
|
+
exception: Exception;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface WebSocketClosedEvent extends PlayerEvent {
|
|
96
|
+
type: PlayerEventType.WEBSOCKET_CLOSED_EVENT;
|
|
97
|
+
code: number;
|
|
98
|
+
byRemote: boolean;
|
|
99
|
+
reason: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface PlayerUpdate {
|
|
103
|
+
op: OpCodes.PLAYER_UPDATE;
|
|
104
|
+
state: {
|
|
105
|
+
connected: boolean;
|
|
106
|
+
position: number;
|
|
107
|
+
time: number;
|
|
108
|
+
ping: number;
|
|
109
|
+
};
|
|
110
|
+
guildId: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface FilterOptions {
|
|
114
|
+
volume?: number;
|
|
115
|
+
equalizer?: Band[];
|
|
116
|
+
karaoke?: KaraokeSettings | null;
|
|
117
|
+
timescale?: TimescaleSettings | null;
|
|
118
|
+
tremolo?: FreqSettings | null;
|
|
119
|
+
vibrato?: FreqSettings | null;
|
|
120
|
+
rotation?: RotationSettings | null;
|
|
121
|
+
distortion?: DistortionSettings | null;
|
|
122
|
+
channelMix?: ChannelMixSettings | null;
|
|
123
|
+
lowPass?: LowPassSettings | null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Interfaces are not final, but types are, and therefore has an index signature
|
|
127
|
+
// https://stackoverflow.com/a/64970740
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
129
|
+
export type PlayerEvents = {
|
|
130
|
+
/**
|
|
131
|
+
* Emitted when the current playing track ends
|
|
132
|
+
* @eventProperty
|
|
133
|
+
*/
|
|
134
|
+
'end': [reason: TrackEndEvent];
|
|
135
|
+
/**
|
|
136
|
+
* Emitted when the current playing track gets stuck due to an error
|
|
137
|
+
* @eventProperty
|
|
138
|
+
*/
|
|
139
|
+
'stuck': [data: TrackStuckEvent];
|
|
140
|
+
/**
|
|
141
|
+
* Emitted when the current websocket connection is closed
|
|
142
|
+
* @eventProperty
|
|
143
|
+
*/
|
|
144
|
+
'closed': [reason: WebSocketClosedEvent];
|
|
145
|
+
/**
|
|
146
|
+
* Emitted when a new track starts
|
|
147
|
+
* @eventProperty
|
|
148
|
+
*/
|
|
149
|
+
'start': [data: TrackStartEvent];
|
|
150
|
+
/**
|
|
151
|
+
* Emitted when there is an error caused by the current playing track
|
|
152
|
+
* @eventProperty
|
|
153
|
+
*/
|
|
154
|
+
'exception': [reason: TrackExceptionEvent];
|
|
155
|
+
/**
|
|
156
|
+
* Emitted when the library manages to resume the player
|
|
157
|
+
* @eventProperty
|
|
158
|
+
*/
|
|
159
|
+
'resumed': [player: Player];
|
|
160
|
+
/**
|
|
161
|
+
* Emitted when a playerUpdate even is received from Lavalink
|
|
162
|
+
* @eventProperty
|
|
163
|
+
*/
|
|
164
|
+
'update': [data: PlayerUpdate];
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Wrapper object around Lavalink
|
|
169
|
+
*/
|
|
170
|
+
export class Player extends TypedEventEmitter<PlayerEvents> {
|
|
171
|
+
/**
|
|
172
|
+
* GuildId of this player
|
|
173
|
+
*/
|
|
174
|
+
public readonly guildId: string;
|
|
175
|
+
/**
|
|
176
|
+
* Lavalink node this player is connected to
|
|
177
|
+
*/
|
|
178
|
+
public node: Node;
|
|
179
|
+
/**
|
|
180
|
+
* Base64 encoded data of the current track
|
|
181
|
+
*/
|
|
182
|
+
public track: string | null;
|
|
183
|
+
/**
|
|
184
|
+
* Global volume of the player
|
|
185
|
+
*/
|
|
186
|
+
public volume: number;
|
|
187
|
+
/**
|
|
188
|
+
* Pause status in current player
|
|
189
|
+
*/
|
|
190
|
+
public paused: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Ping represents the number of milliseconds between heartbeat and ack. Could be `-1` if not connected
|
|
193
|
+
*/
|
|
194
|
+
public ping: number;
|
|
195
|
+
/**
|
|
196
|
+
* Position in ms of current track
|
|
197
|
+
*/
|
|
198
|
+
public position: number;
|
|
199
|
+
/**
|
|
200
|
+
* Filters on current track
|
|
201
|
+
*/
|
|
202
|
+
public filters: FilterOptions;
|
|
203
|
+
|
|
204
|
+
constructor(guildId: string, node: Node) {
|
|
205
|
+
super();
|
|
206
|
+
this.guildId = guildId;
|
|
207
|
+
this.node = node;
|
|
208
|
+
this.track = null;
|
|
209
|
+
this.volume = 100;
|
|
210
|
+
this.paused = false;
|
|
211
|
+
this.position = 0;
|
|
212
|
+
this.ping = 0;
|
|
213
|
+
this.filters = {};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
public get data(): UpdatePlayerInfo {
|
|
217
|
+
const connection = this.node.manager.connections.get(this.guildId)!;
|
|
218
|
+
return {
|
|
219
|
+
guildId: this.guildId,
|
|
220
|
+
playerOptions: {
|
|
221
|
+
track: {
|
|
222
|
+
encoded: this.track
|
|
223
|
+
},
|
|
224
|
+
position: this.position,
|
|
225
|
+
paused: this.paused,
|
|
226
|
+
filters: this.filters,
|
|
227
|
+
voice: {
|
|
228
|
+
token: connection.serverUpdate!.token,
|
|
229
|
+
endpoint: connection.serverUpdate!.endpoint,
|
|
230
|
+
sessionId: connection.sessionId!
|
|
231
|
+
},
|
|
232
|
+
volume: this.volume
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Move player to another node
|
|
239
|
+
* @param name Name of node to move to, or the default ideal node
|
|
240
|
+
* @returns true if the player was moved, false if not
|
|
241
|
+
*/
|
|
242
|
+
public async move(name?: string): Promise<boolean> {
|
|
243
|
+
const connection = this.node.manager.connections.get(this.guildId);
|
|
244
|
+
const node = this.node.manager.nodes.get(name!) ?? this.node.manager.getIdealNode(connection);
|
|
245
|
+
|
|
246
|
+
if (!node && ![ ...this.node.manager.nodes.values() ].some(node => node.state === State.CONNECTED))
|
|
247
|
+
throw new Error('No available nodes to move to');
|
|
248
|
+
|
|
249
|
+
if (!node || node.name === this.node.name || node.state !== State.CONNECTED) return false;
|
|
250
|
+
|
|
251
|
+
let lastNode = this.node.manager.nodes.get(this.node.name);
|
|
252
|
+
if (!lastNode || lastNode.state !== State.CONNECTED)
|
|
253
|
+
lastNode = this.node.manager.getIdealNode(connection);
|
|
254
|
+
|
|
255
|
+
await this.destroy();
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
this.node = node;
|
|
259
|
+
await this.resume();
|
|
260
|
+
return true;
|
|
261
|
+
} catch {
|
|
262
|
+
this.node = lastNode!;
|
|
263
|
+
await this.resume();
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Destroys the player in remote lavalink side
|
|
270
|
+
*/
|
|
271
|
+
public async destroy(): Promise<void> {
|
|
272
|
+
await this.node.rest.destroyPlayer(this.guildId);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Play a new track
|
|
277
|
+
*/
|
|
278
|
+
public playTrack(playerOptions: PlayOptions, noReplace = false): Promise<void> {
|
|
279
|
+
return this.update(playerOptions, noReplace);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Stop the currently playing track
|
|
284
|
+
*/
|
|
285
|
+
public stopTrack(): Promise<void> {
|
|
286
|
+
return this.update({ track: { encoded: null }, position: 0 });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Pause or unpause the currently playing track
|
|
291
|
+
* @param paused Boolean value to specify whether to pause or unpause the current bot user
|
|
292
|
+
*/
|
|
293
|
+
public setPaused(paused = true): Promise<void> {
|
|
294
|
+
return this.update({ paused });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Seek to a specific time in the currently playing track
|
|
299
|
+
* @param position Position to seek to in milliseconds
|
|
300
|
+
*/
|
|
301
|
+
public seekTo(position: number): Promise<void> {
|
|
302
|
+
return this.update({ position });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Sets the global volume of the player
|
|
307
|
+
* @param volume Target volume 0-1000
|
|
308
|
+
*/
|
|
309
|
+
public setGlobalVolume(volume: number): Promise<void> {
|
|
310
|
+
return this.update({ volume });
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Sets the filter volume of the player
|
|
315
|
+
* @param volume Target volume 0.0-5.0
|
|
316
|
+
*/
|
|
317
|
+
async setFilterVolume(volume: number): Promise<void> {
|
|
318
|
+
return this.setFilters({ volume });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Change the equalizer settings applied to the currently playing track
|
|
323
|
+
* @param equalizer An array of objects that conforms to the Bands type that define volumes at different frequencies
|
|
324
|
+
*/
|
|
325
|
+
public async setEqualizer(equalizer: Band[]): Promise<void> {
|
|
326
|
+
return this.setFilters({ equalizer });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Change the karaoke settings applied to the currently playing track
|
|
331
|
+
* @param karaoke An object that conforms to the KaraokeSettings type that defines a range of frequencies to mute
|
|
332
|
+
*/
|
|
333
|
+
public setKaraoke(karaoke?: KaraokeSettings): Promise<void> {
|
|
334
|
+
return this.setFilters({ karaoke: karaoke ?? null });
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Change the timescale settings applied to the currently playing track
|
|
339
|
+
* @param timescale An object that conforms to the TimescaleSettings type that defines the time signature to play the audio at
|
|
340
|
+
*/
|
|
341
|
+
public setTimescale(timescale?: TimescaleSettings): Promise<void> {
|
|
342
|
+
return this.setFilters({ timescale: timescale ?? null });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Change the tremolo settings applied to the currently playing track
|
|
347
|
+
* @param tremolo An object that conforms to the FreqSettings type that defines an oscillation in volume
|
|
348
|
+
*/
|
|
349
|
+
public setTremolo(tremolo?: FreqSettings): Promise<void> {
|
|
350
|
+
return this.setFilters({ tremolo: tremolo ?? null });
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Change the vibrato settings applied to the currently playing track
|
|
355
|
+
* @param vibrato An object that conforms to the FreqSettings type that defines an oscillation in pitch
|
|
356
|
+
*/
|
|
357
|
+
public setVibrato(vibrato?: FreqSettings): Promise<void> {
|
|
358
|
+
return this.setFilters({ vibrato: vibrato ?? null });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Change the rotation settings applied to the currently playing track
|
|
363
|
+
* @param rotation An object that conforms to the RotationSettings type that defines the frequency of audio rotating round the listener
|
|
364
|
+
*/
|
|
365
|
+
public setRotation(rotation?: RotationSettings): Promise<void> {
|
|
366
|
+
return this.setFilters({ rotation: rotation ?? null });
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Change the distortion settings applied to the currently playing track
|
|
371
|
+
* @param distortion An object that conforms to DistortionSettings that defines distortions in the audio
|
|
372
|
+
* @returns The current player instance
|
|
373
|
+
*/
|
|
374
|
+
public setDistortion(distortion?: DistortionSettings): Promise<void> {
|
|
375
|
+
return this.setFilters({ distortion: distortion ?? null });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Change the channel mix settings applied to the currently playing track
|
|
380
|
+
* @param channelMix An object that conforms to ChannelMixSettings that defines how much the left and right channels affect each other (setting all factors to 0.5 causes both channels to get the same audio)
|
|
381
|
+
*/
|
|
382
|
+
public setChannelMix(channelMix?: ChannelMixSettings): Promise<void> {
|
|
383
|
+
return this.setFilters({ channelMix: channelMix ?? null });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Change the low pass settings applied to the currently playing track
|
|
388
|
+
* @param lowPass An object that conforms to LowPassSettings that defines the amount of suppression on higher frequencies
|
|
389
|
+
*/
|
|
390
|
+
public setLowPass(lowPass?: LowPassSettings): Promise<void> {
|
|
391
|
+
return this.setFilters({ lowPass: lowPass ?? null });
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Change the all filter settings applied to the currently playing track
|
|
396
|
+
* @param filters An object that conforms to FilterOptions that defines all filters to apply/modify
|
|
397
|
+
*/
|
|
398
|
+
public setFilters(filters: FilterOptions): Promise<void> {
|
|
399
|
+
return this.update({ filters });
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Clear all filters applied to the currently playing track
|
|
404
|
+
*/
|
|
405
|
+
public clearFilters(): Promise<void> {
|
|
406
|
+
return this.setFilters({
|
|
407
|
+
volume: 1,
|
|
408
|
+
equalizer: [],
|
|
409
|
+
karaoke: null,
|
|
410
|
+
timescale: null,
|
|
411
|
+
tremolo: null,
|
|
412
|
+
vibrato: null,
|
|
413
|
+
rotation: null,
|
|
414
|
+
distortion: null,
|
|
415
|
+
channelMix: null,
|
|
416
|
+
lowPass: null
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Resumes the current track
|
|
422
|
+
* @param options An object that conforms to ResumeOptions that specify behavior on resuming
|
|
423
|
+
* @param noReplace Set it to true if you don't want to replace the currently playing track
|
|
424
|
+
*/
|
|
425
|
+
public async resume(options: ResumeOptions = {}, noReplace = false): Promise<void> {
|
|
426
|
+
const data = this.data;
|
|
427
|
+
|
|
428
|
+
if (typeof options.position === 'number')
|
|
429
|
+
data.playerOptions.position = options.position;
|
|
430
|
+
if (typeof options.endTime === 'number')
|
|
431
|
+
data.playerOptions.endTime = options.endTime;
|
|
432
|
+
if (typeof options.paused === 'boolean')
|
|
433
|
+
data.playerOptions.paused = options.paused;
|
|
434
|
+
if (typeof options.volume === 'number')
|
|
435
|
+
data.playerOptions.volume = options.volume;
|
|
436
|
+
|
|
437
|
+
await this.update(data.playerOptions, noReplace);
|
|
438
|
+
|
|
439
|
+
this.emit('resumed', this);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* If you want to update the whole player yourself, sends raw update player info to lavalink
|
|
444
|
+
* @param playerOptions Options to update the player data
|
|
445
|
+
* @param noReplace Set it to true if you don't want to replace the currently playing track
|
|
446
|
+
*/
|
|
447
|
+
public async update(playerOptions: UpdatePlayerOptions, noReplace = false): Promise<void> {
|
|
448
|
+
const data = {
|
|
449
|
+
guildId: this.guildId,
|
|
450
|
+
noReplace,
|
|
451
|
+
playerOptions
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
await this.node.rest.updatePlayer(data);
|
|
455
|
+
|
|
456
|
+
if (!noReplace) this.paused = false;
|
|
457
|
+
|
|
458
|
+
if (playerOptions.filters) {
|
|
459
|
+
this.filters = { ...this.filters, ...playerOptions.filters };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (typeof playerOptions.track !== 'undefined')
|
|
463
|
+
this.track = playerOptions.track.encoded ?? null;
|
|
464
|
+
if (typeof playerOptions.paused === 'boolean')
|
|
465
|
+
this.paused = playerOptions.paused;
|
|
466
|
+
if (typeof playerOptions.volume === 'number')
|
|
467
|
+
this.volume = playerOptions.volume;
|
|
468
|
+
if (typeof playerOptions.position === 'number')
|
|
469
|
+
this.position = playerOptions.position;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Cleans this player instance
|
|
474
|
+
* @internal
|
|
475
|
+
*/
|
|
476
|
+
public clean(): void {
|
|
477
|
+
this.removeAllListeners();
|
|
478
|
+
this.track = null;
|
|
479
|
+
this.volume = 100;
|
|
480
|
+
this.position = 0;
|
|
481
|
+
this.filters = {};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Sends server update to lavalink
|
|
486
|
+
* @internal
|
|
487
|
+
*/
|
|
488
|
+
public async sendServerUpdate(connection: Connection): Promise<void> {
|
|
489
|
+
const playerUpdate = {
|
|
490
|
+
guildId: this.guildId,
|
|
491
|
+
playerOptions: {
|
|
492
|
+
voice: {
|
|
493
|
+
token: connection.serverUpdate!.token,
|
|
494
|
+
endpoint: connection.serverUpdate!.endpoint,
|
|
495
|
+
sessionId: connection.sessionId!
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
await this.node.rest.updatePlayer(playerUpdate);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Handle player update data
|
|
504
|
+
*/
|
|
505
|
+
public onPlayerUpdate(json: PlayerUpdate): void {
|
|
506
|
+
const { position, ping } = json.state;
|
|
507
|
+
this.position = position;
|
|
508
|
+
this.ping = ping;
|
|
509
|
+
this.emit('update', json);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Handle player events received from Lavalink
|
|
514
|
+
* @param json JSON data from Lavalink
|
|
515
|
+
* @internal
|
|
516
|
+
*/
|
|
517
|
+
public onPlayerEvent(json: TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent): void {
|
|
518
|
+
switch (json.type) {
|
|
519
|
+
case PlayerEventType.TRACK_START_EVENT:
|
|
520
|
+
if (this.track) this.track = json.track.encoded;
|
|
521
|
+
this.emit('start', json);
|
|
522
|
+
break;
|
|
523
|
+
case PlayerEventType.TRACK_END_EVENT:
|
|
524
|
+
this.emit('end', json);
|
|
525
|
+
break;
|
|
526
|
+
case PlayerEventType.TRACK_STUCK_EVENT:
|
|
527
|
+
this.emit('stuck', json);
|
|
528
|
+
break;
|
|
529
|
+
case PlayerEventType.TRACK_EXCEPTION_EVENT:
|
|
530
|
+
this.emit('exception', json);
|
|
531
|
+
break;
|
|
532
|
+
case PlayerEventType.WEBSOCKET_CLOSED_EVENT:
|
|
533
|
+
this.emit('closed', json);
|
|
534
|
+
break;
|
|
535
|
+
default:
|
|
536
|
+
this.node.manager.emit(
|
|
537
|
+
'debug',
|
|
538
|
+
this.node.name,
|
|
539
|
+
`[Player] -> [Node] : Unknown Player Event Type, Data => ${JSON.stringify(json)}`
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|