muthera 1.0.2
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/.github/dependabot.yml +16 -0
- package/.github/workflows/npm-publish.yml +22 -0
- package/LICENSE +15 -0
- package/README.md +124 -0
- package/package.json +31 -0
- package/src/functions/autoPlay.js +171 -0
- package/src/functions/fetchImage.js +57 -0
- package/src/index.d.ts +407 -0
- package/src/index.js +9 -0
- package/src/structures/Muthera.js +191 -0
- package/src/structures/mutheraConnection.js +66 -0
- package/src/structures/mutheraNode.js +226 -0
- package/src/structures/mutheraPlayer.js +524 -0
- package/src/structures/mutheraQueue.js +37 -0
- package/src/structures/mutheraRest.js +98 -0
- package/src/structures/mutheraTrack.js +96 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { Collection } from "@discordjs/collection";
|
|
3
|
+
|
|
4
|
+
export declare class Track {
|
|
5
|
+
constructor(data: any, requester: any, node: Node);
|
|
6
|
+
|
|
7
|
+
public track: String;
|
|
8
|
+
public info: {
|
|
9
|
+
identifier: String;
|
|
10
|
+
seekable: Boolean;
|
|
11
|
+
author: String;
|
|
12
|
+
length: Number;
|
|
13
|
+
stream: Boolean;
|
|
14
|
+
sourceName: String;
|
|
15
|
+
title: String;
|
|
16
|
+
uri: String;
|
|
17
|
+
thumbnail: String | null;
|
|
18
|
+
requester: any;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
public resolve(muthera: muthera): Promise<Track>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RestOptions {
|
|
25
|
+
secure: Boolean;
|
|
26
|
+
host: String;
|
|
27
|
+
port: Number;
|
|
28
|
+
sessionId: String;
|
|
29
|
+
password: String;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface RequestOptions {
|
|
33
|
+
guildId: String;
|
|
34
|
+
data: any;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface RestResponse {
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export declare class Rest extends EventEmitter {
|
|
42
|
+
constructor(muthera: muthera, options: RestOptions);
|
|
43
|
+
public muthera: muthera;
|
|
44
|
+
public url: String
|
|
45
|
+
public sessionId: RestOptions["sessionId"];
|
|
46
|
+
public password: RestOptions["password"];
|
|
47
|
+
public calls: Number;
|
|
48
|
+
|
|
49
|
+
public setSessionId(sessionId: String): void;
|
|
50
|
+
public makeRequest(method: String, endpoint: String, body?: any): Promise<RestResponse | null>;
|
|
51
|
+
public getPlayers(): Promise<RestResponse | null>;
|
|
52
|
+
public updatePlayer(options: RequestOptions): Promise<void>;
|
|
53
|
+
public destroyPlayer(guildId: String): Promise<RestResponse | null>;
|
|
54
|
+
public getTracks(identifier: String): Promise<void>;
|
|
55
|
+
public decodeTrack(track: String, node?: any): Promise<void>;
|
|
56
|
+
public decodeTracks(tracks: any[]): Promise<void>;
|
|
57
|
+
public getStats(): Promise<void>;
|
|
58
|
+
public getInfo(): Promise<void>;
|
|
59
|
+
public getRoutePlannerStatus(): Promise<void>;
|
|
60
|
+
public getRoutePlannerAddress(address: String): Promise<void>;
|
|
61
|
+
public parseResponse(req: any): Promise<RestResponse | null>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export declare class Queue<T> extends Array<T>{
|
|
65
|
+
get size(): Number;
|
|
66
|
+
get first(): T | null;
|
|
67
|
+
|
|
68
|
+
add(track: T): this;
|
|
69
|
+
remove(index: Number): T;
|
|
70
|
+
clear(): void;
|
|
71
|
+
shuffle(): void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface PlayerOptions {
|
|
75
|
+
guildId: String;
|
|
76
|
+
textChannel?: String;
|
|
77
|
+
voiceChannel?: String;
|
|
78
|
+
deaf?: Boolean;
|
|
79
|
+
mute?: Boolean;
|
|
80
|
+
volume?: Number;
|
|
81
|
+
loop?: String;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type LoopOption = "none" | "track" | "queue";
|
|
85
|
+
|
|
86
|
+
export declare class Player extends EventEmitter {
|
|
87
|
+
constructor(muthera: muthera, node: Node, options: PlayerOptions);
|
|
88
|
+
public muthera: muthera;
|
|
89
|
+
public node: Node;
|
|
90
|
+
public options: PlayerOptions;
|
|
91
|
+
public guildId: String;
|
|
92
|
+
public textChannel: String;
|
|
93
|
+
public voiceChannel: String;
|
|
94
|
+
public connection: Connection;
|
|
95
|
+
public deaf: Boolean;
|
|
96
|
+
public mute: Boolean;
|
|
97
|
+
public volume: Number;
|
|
98
|
+
public loop: String;
|
|
99
|
+
public data: {};
|
|
100
|
+
public queue: Queue<Track>;
|
|
101
|
+
public position: Number;
|
|
102
|
+
public current: Track;
|
|
103
|
+
public previous: Track | null;
|
|
104
|
+
public playing: Boolean;
|
|
105
|
+
public paused: Boolean;
|
|
106
|
+
public connected: Boolean;
|
|
107
|
+
public timestamp: Number;
|
|
108
|
+
public ping: Number;
|
|
109
|
+
public isAutoplay: Boolean;
|
|
110
|
+
|
|
111
|
+
public play(): Promise<Player>;
|
|
112
|
+
|
|
113
|
+
public autoplay(player: Player): Promise<Player>;
|
|
114
|
+
|
|
115
|
+
public connect(options?: {
|
|
116
|
+
guildId: String;
|
|
117
|
+
voiceChannel: String;
|
|
118
|
+
deaf?: Boolean;
|
|
119
|
+
mute?: Boolean;
|
|
120
|
+
}): void;
|
|
121
|
+
|
|
122
|
+
public stop(): Player;
|
|
123
|
+
public pause(toggle?: Boolean): Player;
|
|
124
|
+
public seek(position: Number): void;
|
|
125
|
+
public setVolume(volume: Number): Player;
|
|
126
|
+
public setLoop(mode: LoopOption): Player;
|
|
127
|
+
public setTextChannel(channel: String): Player;
|
|
128
|
+
public setVoiceChannel(channel: String, options?: {
|
|
129
|
+
mute?: Boolean;
|
|
130
|
+
deaf?: Boolean;
|
|
131
|
+
}): Player;
|
|
132
|
+
|
|
133
|
+
public disconnect(): Player;
|
|
134
|
+
public destroy(): void;
|
|
135
|
+
private handleEvent(payload: any): void;
|
|
136
|
+
private trackStart(player: Player, track: Track, payload: any): void;
|
|
137
|
+
private trackEnd(player: Player, track: Track, payload: any): void;
|
|
138
|
+
private trackError(player: Player, track: Track, payload: any): void;
|
|
139
|
+
private trackStuck(player: Player, track: Track, payload: any): void;
|
|
140
|
+
private socketClosed(player: Player, payload: any): void;
|
|
141
|
+
private set(key: String, value: any): void;
|
|
142
|
+
private get(key: String): any;
|
|
143
|
+
private send(data: any): void;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type SearchPlatform = "ytsearch" | "ytmsearch" | "scsearch";
|
|
147
|
+
export type nodeResponse = {
|
|
148
|
+
/**
|
|
149
|
+
* Array of Loaded Tracks
|
|
150
|
+
*/
|
|
151
|
+
tracks: Array<Track>;
|
|
152
|
+
/**
|
|
153
|
+
* Load Type - "track", "playlist", "search", "error"
|
|
154
|
+
*/
|
|
155
|
+
loadType: String
|
|
156
|
+
/**
|
|
157
|
+
* Playlist Info
|
|
158
|
+
*/
|
|
159
|
+
playlistInfo?: {
|
|
160
|
+
name: String;
|
|
161
|
+
selectedTrack: Number;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export type mutheraOptions = {
|
|
166
|
+
send: (payload: {
|
|
167
|
+
op: Number;
|
|
168
|
+
d: {
|
|
169
|
+
guild_id: String;
|
|
170
|
+
channel_id: String;
|
|
171
|
+
self_deaf: Boolean;
|
|
172
|
+
self_mute: Boolean;
|
|
173
|
+
}
|
|
174
|
+
}) => void;
|
|
175
|
+
defaultSearchPlatform?: SearchPlatform;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
type k = String;
|
|
179
|
+
type v = any;
|
|
180
|
+
|
|
181
|
+
export declare class muthera extends EventEmitter {
|
|
182
|
+
constructor(client: any, nodes: {
|
|
183
|
+
name?: String;
|
|
184
|
+
host: String;
|
|
185
|
+
port: Number;
|
|
186
|
+
password: String;
|
|
187
|
+
secure: Boolean;
|
|
188
|
+
}, options: mutheraOptions);
|
|
189
|
+
public client: any;
|
|
190
|
+
public nodes: Array<LavalinkNode>;
|
|
191
|
+
public nodeMap: Collection<k, Node>;
|
|
192
|
+
public players: Collection<k, Player>;
|
|
193
|
+
public options: mutheraOptions;
|
|
194
|
+
public clientId: String;
|
|
195
|
+
public initiated: Boolean;
|
|
196
|
+
public send: mutheraOptions["send"];
|
|
197
|
+
public defaultSearchPlatform: String;
|
|
198
|
+
|
|
199
|
+
public readonly leastUsedNodes: Array<LavalinkNode>;
|
|
200
|
+
|
|
201
|
+
public init(clientId: String): this;
|
|
202
|
+
|
|
203
|
+
public createNode(options: any): Node;
|
|
204
|
+
|
|
205
|
+
public destroyNode(identifier: String): void;
|
|
206
|
+
|
|
207
|
+
public updateVoiceState(packet: any): void;
|
|
208
|
+
|
|
209
|
+
public fetchRegion(region: String): Array<LavalinkNode>;
|
|
210
|
+
|
|
211
|
+
public createConnection(options: {
|
|
212
|
+
guildId: String;
|
|
213
|
+
voiceChannel: String;
|
|
214
|
+
textChannel: String;
|
|
215
|
+
deaf?: Boolean;
|
|
216
|
+
}): Player;
|
|
217
|
+
|
|
218
|
+
public createPlayer(node: Node, options: PlayerOptions): Player;
|
|
219
|
+
|
|
220
|
+
public removeConnection(guildId: String): void;
|
|
221
|
+
|
|
222
|
+
public resolve(params: {
|
|
223
|
+
query: String;
|
|
224
|
+
source?: String;
|
|
225
|
+
requester: any;
|
|
226
|
+
}): Promise<nodeResponse>;
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
public get(guildId: String): Player;
|
|
230
|
+
|
|
231
|
+
public on(event: "nodeConnect", listener: (node: Node) => void): this;
|
|
232
|
+
public on(event: "nodeReconnect", listener: (node: Node) => void): this;
|
|
233
|
+
public on(event: "nodeDisconnect", listener: (node: Node, reason: String) => void): this;
|
|
234
|
+
public on(event: "nodeCreate", listener: (node: Node) => void): this;
|
|
235
|
+
public on(event: "nodeDestroy", listener: (node: Node) => void): this;
|
|
236
|
+
public on(event: "nodeError", listener: (node: Node, error: Error) => void): this;
|
|
237
|
+
|
|
238
|
+
public on(event: "trackStart", listener: (player: Player, track: Track, payload: any) => void): this;
|
|
239
|
+
public on(event: "trackEnd", listener: (player: Player, track: Track, payload: any) => void): this;
|
|
240
|
+
public on(event: "trackError", listener: (player: Player, track: Track, payload: any) => void): this;
|
|
241
|
+
public on(event: "trackStuck", listener: (player: Player, track: Track, payload: any) => void): this;
|
|
242
|
+
|
|
243
|
+
public on(event: "socketClosed", listener: (player: Player, payload: any) => void): this;
|
|
244
|
+
|
|
245
|
+
public on(event: "playerCreate", listener: (player: Player) => void): this;
|
|
246
|
+
public on(event: "playerDisconnect", listener: (player: Player) => void): this;
|
|
247
|
+
public on(event: "playerMove", listener: (player: Player, oldChannel: String, newChannel: String) => void): this;
|
|
248
|
+
public on(event: "playerUpdate", listener: (player: Player, payload: any) => void): this;
|
|
249
|
+
|
|
250
|
+
public on(event: "queueEnd", listener: (player: Player) => void): this;
|
|
251
|
+
public on(event: "debug", listener: (message: String) => void): this;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export type LavalinkNode = {
|
|
255
|
+
/**
|
|
256
|
+
* The name of the node
|
|
257
|
+
*/
|
|
258
|
+
name?: String;
|
|
259
|
+
/**
|
|
260
|
+
* The IP of the node
|
|
261
|
+
*/
|
|
262
|
+
host: String;
|
|
263
|
+
/**
|
|
264
|
+
* The port of the node
|
|
265
|
+
*/
|
|
266
|
+
port: Number;
|
|
267
|
+
/**
|
|
268
|
+
* The password of the node
|
|
269
|
+
*/
|
|
270
|
+
password: String;
|
|
271
|
+
/**
|
|
272
|
+
* Is node connection secured by SSL ?
|
|
273
|
+
*/
|
|
274
|
+
secure: Boolean;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export type NodeOptions = {
|
|
278
|
+
/**
|
|
279
|
+
* The send function of the node
|
|
280
|
+
*/
|
|
281
|
+
send: (payload: {
|
|
282
|
+
op: Number;
|
|
283
|
+
d: {
|
|
284
|
+
guild_id: String;
|
|
285
|
+
channel_id: String;
|
|
286
|
+
self_deaf: Boolean;
|
|
287
|
+
self_mute: Boolean;
|
|
288
|
+
}
|
|
289
|
+
}) => void;
|
|
290
|
+
/**
|
|
291
|
+
* The resume key of the node
|
|
292
|
+
*/
|
|
293
|
+
resumeKey?: String;
|
|
294
|
+
/**
|
|
295
|
+
* The session id of the node
|
|
296
|
+
*/
|
|
297
|
+
sessionId?: String;
|
|
298
|
+
/**
|
|
299
|
+
* The resume timeout of the node
|
|
300
|
+
*/
|
|
301
|
+
resumeTimeout?: Number;
|
|
302
|
+
/**
|
|
303
|
+
* The reconnect timeout of the node
|
|
304
|
+
*/
|
|
305
|
+
reconnectTimeout?: Number;
|
|
306
|
+
/**
|
|
307
|
+
* The reconnect tries of the node
|
|
308
|
+
*/
|
|
309
|
+
reconnectTries?: Number;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export declare class Node {
|
|
313
|
+
constructor(muthera: muthera, node: LavalinkNode, options: NodeOptions);
|
|
314
|
+
public muthera: muthera;
|
|
315
|
+
|
|
316
|
+
public name: LavalinkNode["name"];
|
|
317
|
+
public host: LavalinkNode["host"];
|
|
318
|
+
public port: LavalinkNode["port"];
|
|
319
|
+
public password: LavalinkNode["password"];
|
|
320
|
+
public secure: LavalinkNode["secure"];
|
|
321
|
+
|
|
322
|
+
public rest: Rest;
|
|
323
|
+
public wsUrl: String;
|
|
324
|
+
public restUrl: String;
|
|
325
|
+
private ws: null;
|
|
326
|
+
|
|
327
|
+
public send: NodeOptions["send"];
|
|
328
|
+
public resumeKey: NodeOptions["resumeKey"];
|
|
329
|
+
public sessionId: NodeOptions["sessionId"];
|
|
330
|
+
public region: String | null;
|
|
331
|
+
public resumeTimeout: NodeOptions["resumeTimeout"];
|
|
332
|
+
public reconnectTimeout: NodeOptions["reconnectTimeout"];
|
|
333
|
+
public reconnectTries: NodeOptions["reconnectTries"];
|
|
334
|
+
|
|
335
|
+
public reconnectAttempt: Number;
|
|
336
|
+
public reconnectAttempted: Number;
|
|
337
|
+
|
|
338
|
+
public connected: Boolean;
|
|
339
|
+
public reconnecting: Boolean;
|
|
340
|
+
public stats: {
|
|
341
|
+
players: 0,
|
|
342
|
+
playingPlayers: 0,
|
|
343
|
+
uptime: 0,
|
|
344
|
+
memory: {
|
|
345
|
+
free: 0,
|
|
346
|
+
used: 0,
|
|
347
|
+
allocated: 0,
|
|
348
|
+
reservable: 0,
|
|
349
|
+
},
|
|
350
|
+
cpu: {
|
|
351
|
+
cores: 0,
|
|
352
|
+
systemLoad: 0,
|
|
353
|
+
lavalinkLoad: 0,
|
|
354
|
+
},
|
|
355
|
+
frameStats: {
|
|
356
|
+
sent: 0,
|
|
357
|
+
nulled: 0,
|
|
358
|
+
deficit: 0,
|
|
359
|
+
},
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
public connect(): void;
|
|
363
|
+
public open(): void;
|
|
364
|
+
public error(event: any): void;
|
|
365
|
+
public message(msg: any): void;
|
|
366
|
+
public close(event: any, reason: String): void;
|
|
367
|
+
public reconnect(): void;
|
|
368
|
+
public disconnect(): void;
|
|
369
|
+
readonly penalties: Number;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export type Voice = {
|
|
373
|
+
/**
|
|
374
|
+
* The voice session id
|
|
375
|
+
*/
|
|
376
|
+
sessionId: String,
|
|
377
|
+
/**
|
|
378
|
+
* The voice event
|
|
379
|
+
*/
|
|
380
|
+
event: null,
|
|
381
|
+
/**
|
|
382
|
+
* The voice endpoint
|
|
383
|
+
*/
|
|
384
|
+
endpoint: String
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export declare class Connection {
|
|
388
|
+
constructor(player: Player);
|
|
389
|
+
public player: Player;
|
|
390
|
+
public sessionId: String;
|
|
391
|
+
public voice: Voice;
|
|
392
|
+
public region: String;
|
|
393
|
+
public self_deaf: Boolean;
|
|
394
|
+
public self_mute: Boolean;
|
|
395
|
+
public voiceChannel: String;
|
|
396
|
+
|
|
397
|
+
public setServerUpdate(data: { endpoint: String; token: String }): void;
|
|
398
|
+
|
|
399
|
+
public setStateUpdate(data: {
|
|
400
|
+
session_id: String;
|
|
401
|
+
channel_id: String;
|
|
402
|
+
self_deaf: Boolean;
|
|
403
|
+
self_mute: Boolean;
|
|
404
|
+
}): void;
|
|
405
|
+
|
|
406
|
+
private updatePlayerVoiceData(): void;
|
|
407
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const { Connection } = require("./structures/mutheraConnection");
|
|
2
|
+
const { Node } = require("./structures/mutheraNode");
|
|
3
|
+
const { Muthera } = require("./structures/Muthera");
|
|
4
|
+
const { Player } = require("./structures/mutheraPlayer");
|
|
5
|
+
const { Queue } = require("./structures/mutheraQueue");
|
|
6
|
+
const { Rest } = require("./structures/mutheraRest");
|
|
7
|
+
const { Track } = require("./structures/mutheraTrack");
|
|
8
|
+
|
|
9
|
+
module.exports = { Connection, Node, Muthera, Player, Queue, Rest, Track };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
const { EventEmitter } = require("events");
|
|
2
|
+
const { Node } = require("./mutheraNode");
|
|
3
|
+
const { Player } = require("./mutheraPlayer");
|
|
4
|
+
const { Track } = require("./mutheraTrack");
|
|
5
|
+
const { Collection } = require("@discordjs/collection");
|
|
6
|
+
|
|
7
|
+
class Muthera extends EventEmitter {
|
|
8
|
+
constructor(client, nodes, options) {
|
|
9
|
+
super();
|
|
10
|
+
if (!client)
|
|
11
|
+
throw new Error("Client option must be present to initialize muthera.");
|
|
12
|
+
if (!nodes)
|
|
13
|
+
throw new Error("Node option must be present to initialize muthera.");
|
|
14
|
+
if (!options.send)
|
|
15
|
+
throw new Error("Send function must be present to initialize muthera.");
|
|
16
|
+
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.nodes = nodes;
|
|
19
|
+
this.nodeMap = new Collection();
|
|
20
|
+
this.players = new Collection();
|
|
21
|
+
this.options = options;
|
|
22
|
+
this.clientId = null;
|
|
23
|
+
this.initiated = false;
|
|
24
|
+
this.send = options.send || null;
|
|
25
|
+
this.defaultSearchPlatform = options.defaultSearchPlatform || "ytsearch";
|
|
26
|
+
this.tracks = [];
|
|
27
|
+
this.loadType = null;
|
|
28
|
+
this.playlistInfo = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get leastUsedNodes() {
|
|
32
|
+
return [...this.nodeMap.values()]
|
|
33
|
+
.filter((node) => node.connected)
|
|
34
|
+
.sort((a, b) => b.rest.calls - a.rest.calls);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
init(clientId) {
|
|
38
|
+
if (this.initiated) return this;
|
|
39
|
+
this.clientId = clientId;
|
|
40
|
+
this.nodes.forEach((node) => this.createNode(node));
|
|
41
|
+
this.initiated = true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
createNode(options) {
|
|
45
|
+
const node = new Node(this, options, this.options);
|
|
46
|
+
this.nodeMap.set(options.name || options.host, node);
|
|
47
|
+
node.connect();
|
|
48
|
+
|
|
49
|
+
this.emit("nodeCreate", node);
|
|
50
|
+
return node;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
destroyNode(identifier) {
|
|
54
|
+
const node = this.nodeMap.get(identifier);
|
|
55
|
+
if (!node) return;
|
|
56
|
+
node.disconnect();
|
|
57
|
+
this.nodeMap.delete(identifier);
|
|
58
|
+
this.emit("nodeDestroy", node);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
updateVoiceState(packet) {
|
|
62
|
+
if (!["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(packet.t))
|
|
63
|
+
return;
|
|
64
|
+
const player = this.players.get(packet.d.guild_id);
|
|
65
|
+
if (!player) return;
|
|
66
|
+
|
|
67
|
+
if (packet.t === "VOICE_SERVER_UPDATE") {
|
|
68
|
+
player.connection.setServerUpdate(packet.d);
|
|
69
|
+
} else if (packet.t === "VOICE_STATE_UPDATE") {
|
|
70
|
+
if (packet.d.user_id !== this.clientId) return;
|
|
71
|
+
player.connection.setStateUpdate(packet.d);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
fetchRegion(region) {
|
|
76
|
+
const nodesByRegion = [...this.nodeMap.values()]
|
|
77
|
+
.filter(
|
|
78
|
+
(node) =>
|
|
79
|
+
node.connected && node.regions?.includes(region?.toLowerCase())
|
|
80
|
+
)
|
|
81
|
+
.sort((a, b) => {
|
|
82
|
+
const aLoad = a.stats.cpu
|
|
83
|
+
? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100
|
|
84
|
+
: 0;
|
|
85
|
+
const bLoad = b.stats.cpu
|
|
86
|
+
? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100
|
|
87
|
+
: 0;
|
|
88
|
+
return aLoad - bLoad;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return nodesByRegion;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
createConnection(options) {
|
|
95
|
+
if (!this.initiated)
|
|
96
|
+
throw new Error("You have to initialize muthera in your event.");
|
|
97
|
+
|
|
98
|
+
const player = this.players.get(options.guildId);
|
|
99
|
+
if (player) return player;
|
|
100
|
+
|
|
101
|
+
if (this.leastUsedNodes.length === 0)
|
|
102
|
+
throw new Error("No nodes are available.");
|
|
103
|
+
|
|
104
|
+
let node;
|
|
105
|
+
if (options.node) {
|
|
106
|
+
node = this.nodeMap.get(options.node);
|
|
107
|
+
} else {
|
|
108
|
+
node = this.nodeMap.get(this.leastUsedNodes[0].name);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!node) throw new Error("No nodes are available.");
|
|
112
|
+
|
|
113
|
+
return this.createPlayer(node, options);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
createPlayer(node, options) {
|
|
117
|
+
const player = new Player(this, node, options);
|
|
118
|
+
this.players.set(options.guildId, player);
|
|
119
|
+
|
|
120
|
+
player.connect(options);
|
|
121
|
+
|
|
122
|
+
this.emit("playerCreate", player);
|
|
123
|
+
return player;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
destroyPlayer(guildId) {
|
|
127
|
+
const player = this.players.get(guildId);
|
|
128
|
+
if (!player) return;
|
|
129
|
+
player.destroy();
|
|
130
|
+
this.players.delete(guildId);
|
|
131
|
+
|
|
132
|
+
this.emit("playerDestroy", player);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
removeConnection(guildId) {
|
|
136
|
+
this.players.get(guildId)?.destroy();
|
|
137
|
+
this.players.delete(guildId);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async resolve({ query, source, requester }) {
|
|
141
|
+
try {
|
|
142
|
+
if (!this.initiated)
|
|
143
|
+
throw new Error("You have to initialize muthera in your event.");
|
|
144
|
+
|
|
145
|
+
const sources = source || this.defaultSearchPlatform;
|
|
146
|
+
|
|
147
|
+
const node = this.leastUsedNodes[0];
|
|
148
|
+
if (!node) throw new Error("No nodes are available.");
|
|
149
|
+
|
|
150
|
+
const regex = /^https?:\/\//;
|
|
151
|
+
const identifier = regex.test(query) ? query : `${sources}:${query}`;
|
|
152
|
+
|
|
153
|
+
let response = await node.rest.makeRequest(
|
|
154
|
+
`GET`,
|
|
155
|
+
`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (response.loadType === "track") {
|
|
159
|
+
this.tracks = [new Track(response.data, requester, node)];
|
|
160
|
+
} else if (response.loadType === "playlist") {
|
|
161
|
+
this.tracks = response.data.tracks.map(
|
|
162
|
+
(track) => new Track(track, requester, node)
|
|
163
|
+
);
|
|
164
|
+
} else if (
|
|
165
|
+
response.loadType === "error" ||
|
|
166
|
+
response.loadType === "empty"
|
|
167
|
+
) {
|
|
168
|
+
this.tracks = null;
|
|
169
|
+
} else {
|
|
170
|
+
this.tracks = response.data.map(
|
|
171
|
+
(track) => new Track(track, requester, node)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.playlistInfo = response.data.info ?? null;
|
|
176
|
+
this.loadType = response.loadType ?? null;
|
|
177
|
+
return this;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new Error(error);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
get(guildId) {
|
|
184
|
+
const player = this.players.get(guildId);
|
|
185
|
+
if (!player)
|
|
186
|
+
throw new Error(`No player were found for guildId: ${guildId}.`);
|
|
187
|
+
return player;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = { Muthera };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
class Connection {
|
|
2
|
+
/**
|
|
3
|
+
* @param {import ("../index").Player} player
|
|
4
|
+
*/
|
|
5
|
+
constructor(player) {
|
|
6
|
+
this.player = player;
|
|
7
|
+
this.sessionId = null;
|
|
8
|
+
this.voice = {
|
|
9
|
+
event: null,
|
|
10
|
+
endpoint: null,
|
|
11
|
+
sessionId: null,
|
|
12
|
+
};
|
|
13
|
+
this.self_deaf = false;
|
|
14
|
+
this.self_mute = false;
|
|
15
|
+
this.region = null;
|
|
16
|
+
this.voiceChannel = player.voiceChannel;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setServerUpdate(data) {
|
|
20
|
+
const { endpoint, token } = data;
|
|
21
|
+
|
|
22
|
+
if (!endpoint) throw new Error("Invalid session. Please try again.");
|
|
23
|
+
|
|
24
|
+
this.voice.endpoint = endpoint;
|
|
25
|
+
this.voice.token = token;
|
|
26
|
+
this.region = endpoint.split(".").shift()?.replace(/[0-9]/g, "") || null;
|
|
27
|
+
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
this.player.pause(false)
|
|
30
|
+
}, 5000);
|
|
31
|
+
|
|
32
|
+
this.updatePlayerVoiceData();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setStateUpdate(data) {
|
|
36
|
+
const { session_id, channel_id, self_deaf, self_mute } = data;
|
|
37
|
+
|
|
38
|
+
if (
|
|
39
|
+
this.player.voiceChannel &&
|
|
40
|
+
channel_id &&
|
|
41
|
+
this.player.voiceChannel !== channel_id
|
|
42
|
+
) {
|
|
43
|
+
this.player.muthera.emit("playerMove", this.player.voiceChannel, channel_id);
|
|
44
|
+
this.player.voiceChannel = channel_id;
|
|
45
|
+
this.voiceChannel = channel_id;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.self_deaf = self_deaf;
|
|
49
|
+
this.self_mute = self_mute;
|
|
50
|
+
this.voice.sessionId = session_id || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
updatePlayerVoiceData() {
|
|
54
|
+
this.player.muthera.emit(
|
|
55
|
+
"debug",
|
|
56
|
+
this.player.node.name,
|
|
57
|
+
`Update player data: ${JSON.stringify({ voice: this.voice })}`
|
|
58
|
+
);
|
|
59
|
+
this.player.node.rest.updatePlayer({
|
|
60
|
+
guildId: this.player.guildId,
|
|
61
|
+
data: { voice: this.voice },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = { Connection };
|