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
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
const { EventEmitter } = require("events");
|
|
2
|
+
const { Connection } = require("./mutheraConnection");
|
|
3
|
+
const { Queue } = require("./mutheraQueue");
|
|
4
|
+
const {
|
|
5
|
+
scAutoPlay,
|
|
6
|
+
spAutoPlay,
|
|
7
|
+
amAutoPlay,
|
|
8
|
+
dzAutoPlay,
|
|
9
|
+
} = require("../functions/autoPlay");
|
|
10
|
+
|
|
11
|
+
class Player extends EventEmitter {
|
|
12
|
+
constructor(muthera, node, options) {
|
|
13
|
+
super();
|
|
14
|
+
this.muthera = muthera;
|
|
15
|
+
this.node = node;
|
|
16
|
+
this.sessionId = node.sessionId;
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.guildId = options.guildId;
|
|
19
|
+
this.textChannel = options.textChannel;
|
|
20
|
+
this.voiceChannel = options.voiceChannel;
|
|
21
|
+
this.connection = new Connection(this);
|
|
22
|
+
this.mute = options.mute ?? false;
|
|
23
|
+
this.deaf = options.deaf ?? false;
|
|
24
|
+
this.volume = options.volume ?? 100;
|
|
25
|
+
this.loop = options.loop ?? "none";
|
|
26
|
+
this.data = {};
|
|
27
|
+
this.queue = new Queue();
|
|
28
|
+
this.position = 0;
|
|
29
|
+
this.current = null;
|
|
30
|
+
this.previous = null;
|
|
31
|
+
this.playing = false;
|
|
32
|
+
this.paused = false;
|
|
33
|
+
this.connected = false;
|
|
34
|
+
this.timestamp = 0;
|
|
35
|
+
this.ping = 0;
|
|
36
|
+
this.isAutoplay = false;
|
|
37
|
+
|
|
38
|
+
this.on("playerUpdate", (packet) => {
|
|
39
|
+
(this.connected = packet.state.connected),
|
|
40
|
+
(this.position = packet.state.position),
|
|
41
|
+
(this.ping = packet.state.ping);
|
|
42
|
+
this.timestamp = packet.state.time;
|
|
43
|
+
|
|
44
|
+
this.muthera.emit("playerUpdate", this, packet);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
this.on("event", (data) => {
|
|
48
|
+
this.handleEvent(data);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async play() {
|
|
53
|
+
if (!this.connected) throw new Error("Player are not initialize.");
|
|
54
|
+
if (!this.queue.length) return;
|
|
55
|
+
|
|
56
|
+
this.current = this.queue.shift();
|
|
57
|
+
|
|
58
|
+
if (!this.current.track) {
|
|
59
|
+
this.current = await this.current.resolve(this.muthera);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.playing = true;
|
|
63
|
+
this.position = 0;
|
|
64
|
+
|
|
65
|
+
const { track } = this.current;
|
|
66
|
+
|
|
67
|
+
this.node.rest.updatePlayer({
|
|
68
|
+
guildId: this.guildId,
|
|
69
|
+
data: {
|
|
70
|
+
encodedTrack: track,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param {this} player
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
async autoplay(player) {
|
|
83
|
+
if (!player) {
|
|
84
|
+
if (player == null) {
|
|
85
|
+
this.isAutoplay = false;
|
|
86
|
+
return this;
|
|
87
|
+
} else if (player == false) {
|
|
88
|
+
this.isAutoplay = false;
|
|
89
|
+
return this;
|
|
90
|
+
} else throw new Error("No argument provided.");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.isAutoplay = true;
|
|
94
|
+
|
|
95
|
+
if (player.previous) {
|
|
96
|
+
if (player.previous.info.sourceName === "youtube") {
|
|
97
|
+
try {
|
|
98
|
+
let data = `https://www.youtube.com/watch?v=${player.previous.info.identifier}&list=RD${player.previous.info.identifier}`;
|
|
99
|
+
let response = await this.muthera.resolve({
|
|
100
|
+
query: data,
|
|
101
|
+
source: "ytmsearch",
|
|
102
|
+
requester: player.previous.info.requester,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
!response ||
|
|
107
|
+
!response.tracks ||
|
|
108
|
+
["error", "empty"].includes(response.loadType)
|
|
109
|
+
)
|
|
110
|
+
return this.stop();
|
|
111
|
+
|
|
112
|
+
let track =
|
|
113
|
+
response.tracks[
|
|
114
|
+
Math.floor(Math.random() * Math.floor(response.tracks.length))
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
if (this.connected) {
|
|
118
|
+
this.queue.push(track);
|
|
119
|
+
await this.play();
|
|
120
|
+
} else {
|
|
121
|
+
return this.stop();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return this;
|
|
125
|
+
} catch (e) {
|
|
126
|
+
return this.stop();
|
|
127
|
+
}
|
|
128
|
+
} else if (player.previous.info.sourceName === "soundcloud") {
|
|
129
|
+
try {
|
|
130
|
+
scAutoPlay(player.previous.info.uri).then(async (data) => {
|
|
131
|
+
let response = await this.muthera.resolve({
|
|
132
|
+
query: data,
|
|
133
|
+
source: "scsearch",
|
|
134
|
+
requester: player.previous.info.requester,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (
|
|
138
|
+
!response ||
|
|
139
|
+
!response.tracks ||
|
|
140
|
+
["error", "empty"].includes(response.loadType)
|
|
141
|
+
)
|
|
142
|
+
return this.stop();
|
|
143
|
+
|
|
144
|
+
let track =
|
|
145
|
+
response.tracks[
|
|
146
|
+
Math.floor(Math.random() * Math.floor(response.tracks.length))
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
if (this.connected) {
|
|
150
|
+
this.queue.push(track);
|
|
151
|
+
await this.play();
|
|
152
|
+
} else {
|
|
153
|
+
return this.stop();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return this;
|
|
157
|
+
});
|
|
158
|
+
} catch (e) {
|
|
159
|
+
console.log(e);
|
|
160
|
+
return this.stop();
|
|
161
|
+
}
|
|
162
|
+
} else if (player.previous.info.sourceName === "deezer") {
|
|
163
|
+
try {
|
|
164
|
+
const data = await dzAutoPlay(player.previous.info.identifier);
|
|
165
|
+
if (!data) return this.stop();
|
|
166
|
+
|
|
167
|
+
const response = await this.muthera.resolve({
|
|
168
|
+
query: data,
|
|
169
|
+
requester: player.previous.info.requester,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
!response ||
|
|
174
|
+
!response.tracks ||
|
|
175
|
+
["error", "empty"].includes(response.loadType)
|
|
176
|
+
)
|
|
177
|
+
return this.stop();
|
|
178
|
+
|
|
179
|
+
const track =
|
|
180
|
+
response.tracks[Math.floor(Math.random() * response.tracks.length)];
|
|
181
|
+
|
|
182
|
+
if (this.connected) {
|
|
183
|
+
this.queue.push(track);
|
|
184
|
+
await this.play();
|
|
185
|
+
} else {
|
|
186
|
+
return this.stop();
|
|
187
|
+
}
|
|
188
|
+
return this;
|
|
189
|
+
} catch (e) {
|
|
190
|
+
console.log(e);
|
|
191
|
+
return this.stop();
|
|
192
|
+
}
|
|
193
|
+
} else if (player.previous.info.sourceName === "applemusic") {
|
|
194
|
+
try {
|
|
195
|
+
const data = await amAutoPlay(player.previous.info.identifier);
|
|
196
|
+
|
|
197
|
+
const randomTrack = data[Math.floor(Math.random() * data.length)];
|
|
198
|
+
|
|
199
|
+
const trackUrl = randomTrack.trackViewUrl;
|
|
200
|
+
|
|
201
|
+
const response = await this.muthera.resolve({
|
|
202
|
+
query: trackUrl,
|
|
203
|
+
requester: player.previous.info.requester,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
!response ||
|
|
208
|
+
!response.tracks ||
|
|
209
|
+
["error", "empty"].includes(response.loadType)
|
|
210
|
+
)
|
|
211
|
+
return this.stop();
|
|
212
|
+
|
|
213
|
+
const track =
|
|
214
|
+
response.tracks[Math.floor(Math.random() * response.tracks.length)];
|
|
215
|
+
|
|
216
|
+
if (this.connected) {
|
|
217
|
+
this.queue.push(track);
|
|
218
|
+
await this.play();
|
|
219
|
+
} else {
|
|
220
|
+
return this.stop();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return this;
|
|
224
|
+
} catch (e) {
|
|
225
|
+
console.log(e);
|
|
226
|
+
return this.stop();
|
|
227
|
+
}
|
|
228
|
+
} else if (player.previous.info.sourceName === "spotify") {
|
|
229
|
+
try {
|
|
230
|
+
// Use YouTube Music search as fallback for Spotify autoplay since Spotify API is blocked
|
|
231
|
+
const title = player.previous.info.title || '';
|
|
232
|
+
const artist = player.previous.info.author || '';
|
|
233
|
+
|
|
234
|
+
// Create multiple search strategies for better results
|
|
235
|
+
const searchQueries = [
|
|
236
|
+
`${artist} similar songs`,
|
|
237
|
+
`${artist} music mix`,
|
|
238
|
+
`music like ${title}`,
|
|
239
|
+
`${artist} playlist`,
|
|
240
|
+
`${title} ${artist} radio`
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
// Try different search queries until we find tracks
|
|
244
|
+
let response = null;
|
|
245
|
+
for (const query of searchQueries) {
|
|
246
|
+
response = await this.muthera.resolve({
|
|
247
|
+
query: query,
|
|
248
|
+
source: "ytmsearch",
|
|
249
|
+
requester: player.previous.info.requester,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
if (response && response.tracks && response.tracks.length > 0 &&
|
|
253
|
+
!["error", "empty"].includes(response.loadType)) {
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (
|
|
259
|
+
!response ||
|
|
260
|
+
!response.tracks ||
|
|
261
|
+
["error", "empty"].includes(response.loadType) ||
|
|
262
|
+
response.tracks.length === 0
|
|
263
|
+
)
|
|
264
|
+
return this.stop();
|
|
265
|
+
|
|
266
|
+
// Filter out tracks that are too similar to the current one
|
|
267
|
+
let availableTracks = response.tracks.filter(track =>
|
|
268
|
+
track.info.title.toLowerCase() !== title.toLowerCase()
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
// If no different tracks found, use all tracks but skip first one
|
|
272
|
+
if (availableTracks.length === 0) {
|
|
273
|
+
availableTracks = response.tracks.slice(1);
|
|
274
|
+
if (availableTracks.length === 0) availableTracks = response.tracks;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let track = availableTracks[Math.floor(Math.random() * availableTracks.length)];
|
|
278
|
+
|
|
279
|
+
if (this.connected) {
|
|
280
|
+
this.queue.push(track);
|
|
281
|
+
await this.play();
|
|
282
|
+
} else {
|
|
283
|
+
return this.stop();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return this;
|
|
287
|
+
} catch (e) {
|
|
288
|
+
console.log('Spotify autoplay error:', e);
|
|
289
|
+
return this.stop();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
} else return this;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
connect(options = this) {
|
|
296
|
+
const { guildId, voiceChannel, deaf = true, mute = false } = options;
|
|
297
|
+
this.send({
|
|
298
|
+
guild_id: guildId,
|
|
299
|
+
channel_id: voiceChannel,
|
|
300
|
+
self_deaf: deaf,
|
|
301
|
+
self_mute: mute,
|
|
302
|
+
});
|
|
303
|
+
this.connected = true;
|
|
304
|
+
this.muthera.emit(
|
|
305
|
+
"debug",
|
|
306
|
+
this.guildId,
|
|
307
|
+
"Player has been successfully connected."
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
stop() {
|
|
312
|
+
this.position = 0;
|
|
313
|
+
this.playing = false;
|
|
314
|
+
this.node.rest.updatePlayer({
|
|
315
|
+
guildId: this.guildId,
|
|
316
|
+
data: { encodedTrack: null },
|
|
317
|
+
});
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
pause(toggle = true) {
|
|
322
|
+
this.node.rest.updatePlayer({
|
|
323
|
+
guildId: this.guildId,
|
|
324
|
+
data: { paused: toggle },
|
|
325
|
+
});
|
|
326
|
+
this.playing = !toggle;
|
|
327
|
+
this.paused = toggle;
|
|
328
|
+
return this;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
seek(position) {
|
|
332
|
+
const trackLength = this.current.info.length;
|
|
333
|
+
this.position = Math.max(0, Math.min(trackLength, position));
|
|
334
|
+
this.node.rest.updatePlayer({ guildId: this.guildId, data: { position } });
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
setVolume(volume) {
|
|
338
|
+
if (volume < 0 || volume > 100) {
|
|
339
|
+
throw new Error("Volume number must be between 0 to 100.");
|
|
340
|
+
}
|
|
341
|
+
this.node.rest.updatePlayer({ guildId: this.guildId, data: { volume } });
|
|
342
|
+
this.volume = volume;
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
setLoop(mode) {
|
|
347
|
+
if (!mode) {
|
|
348
|
+
throw new Error("You must provide an argument to set loop.");
|
|
349
|
+
}
|
|
350
|
+
if (!["none", "track", "queue"].includes(mode)) {
|
|
351
|
+
throw new Error("Set loop rguments must be 'none', 'track', or 'queue'");
|
|
352
|
+
}
|
|
353
|
+
this.loop = mode;
|
|
354
|
+
return this;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
setTextChannel(channel) {
|
|
358
|
+
if (typeof channel !== "string")
|
|
359
|
+
throw new TypeError("Channel must be present and a non-empty string.");
|
|
360
|
+
this.textChannel = channel;
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
setVoiceChannel(channel, options) {
|
|
365
|
+
if (typeof channel !== "string")
|
|
366
|
+
throw new TypeError("Channel must be present and a non-empty string.");
|
|
367
|
+
|
|
368
|
+
if (this.connected && channel === this.voiceChannel) {
|
|
369
|
+
throw new ReferenceError(
|
|
370
|
+
`Player is already connected to channel: ${channel}.`
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
this.voiceChannel = channel;
|
|
374
|
+
|
|
375
|
+
if (options) {
|
|
376
|
+
this.mute = options.mute ?? this.mute;
|
|
377
|
+
this.deaf = options.deaf ?? this.deaf;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
this.connect({
|
|
381
|
+
deaf: this.deaf,
|
|
382
|
+
guildId: this.guildId,
|
|
383
|
+
voiceChannel: this.voiceChannel,
|
|
384
|
+
textChannel: this.textChannel,
|
|
385
|
+
mute: this.mute,
|
|
386
|
+
});
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
disconnect() {
|
|
391
|
+
if (!this.voiceChannel) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
this.connected = false;
|
|
395
|
+
this.send({
|
|
396
|
+
guild_id: this.guildId,
|
|
397
|
+
channel_id: null,
|
|
398
|
+
self_mute: false,
|
|
399
|
+
self_deaf: false,
|
|
400
|
+
});
|
|
401
|
+
this.muthera.emit("queueEnd", this);
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
destroy() {
|
|
406
|
+
if (!this.voiceChannel) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
this.connected = false;
|
|
410
|
+
this.send({
|
|
411
|
+
guild_id: this.guildId,
|
|
412
|
+
channel_id: null,
|
|
413
|
+
self_mute: false,
|
|
414
|
+
self_deaf: false,
|
|
415
|
+
});
|
|
416
|
+
this.node.rest.destroyPlayer(this.guildId);
|
|
417
|
+
this.muthera.emit("playerDisconnect", this);
|
|
418
|
+
this.muthera.emit(
|
|
419
|
+
"debug",
|
|
420
|
+
this.guildId,
|
|
421
|
+
"Destroyed the player and clear the queue."
|
|
422
|
+
);
|
|
423
|
+
this.muthera.players.delete(this.guildId);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async handleEvent(payload) {
|
|
427
|
+
const player = this.muthera.players.get(payload.guildId);
|
|
428
|
+
if (!player) return;
|
|
429
|
+
const track = this.current;
|
|
430
|
+
track.info.thumbnail = await track.info.thumbnail;
|
|
431
|
+
|
|
432
|
+
switch (payload.type) {
|
|
433
|
+
case "TrackStartEvent":
|
|
434
|
+
this.trackStart(player, track, payload);
|
|
435
|
+
break;
|
|
436
|
+
case "TrackEndEvent":
|
|
437
|
+
this.trackEnd(player, track, payload);
|
|
438
|
+
break;
|
|
439
|
+
case "TrackExceptionEvent":
|
|
440
|
+
this.trackError(player, track, payload);
|
|
441
|
+
break;
|
|
442
|
+
case "TrackStuckEvent":
|
|
443
|
+
this.trackStuck(player, track, payload);
|
|
444
|
+
break;
|
|
445
|
+
case "WebSocketClosedEvent":
|
|
446
|
+
this.socketClosed(player, payload);
|
|
447
|
+
break;
|
|
448
|
+
default:
|
|
449
|
+
const error = new Error(
|
|
450
|
+
`Node encountered an unknown event: '${payload.type}'`
|
|
451
|
+
);
|
|
452
|
+
this.muthera.emit("nodeError", this, error);
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
trackStart(player, track, payload) {
|
|
458
|
+
this.playing = true;
|
|
459
|
+
this.paused = false;
|
|
460
|
+
this.muthera.emit("trackStart", player, track, payload);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
trackEnd(player, track, payload) {
|
|
464
|
+
this.previous = track;
|
|
465
|
+
if (this.loop === "track") {
|
|
466
|
+
player.queue.unshift(this.previous);
|
|
467
|
+
this.muthera.emit("trackEnd", player, track, payload);
|
|
468
|
+
return player.play();
|
|
469
|
+
} else if (track && this.loop === "queue") {
|
|
470
|
+
player.queue.push(this.previous);
|
|
471
|
+
this.muthera.emit("trackEnd", player, track, payload);
|
|
472
|
+
return player.play();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (player.queue.length === 0) {
|
|
476
|
+
this.playing = false;
|
|
477
|
+
return this.muthera.emit("queueEnd", player);
|
|
478
|
+
} else if (player.queue.length > 0) {
|
|
479
|
+
this.muthera.emit("trackEnd", player, track, payload);
|
|
480
|
+
return player.play();
|
|
481
|
+
}
|
|
482
|
+
this.playing = false;
|
|
483
|
+
this.muthera.emit("queueEnd", player);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
trackError(player, track, payload) {
|
|
487
|
+
this.muthera.emit("trackError", player, track, payload);
|
|
488
|
+
this.stop();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
trackStuck(player, track, payload) {
|
|
492
|
+
this.muthera.emit("trackStuck", player, track, payload);
|
|
493
|
+
this.stop();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
socketClosed(player, payload) {
|
|
497
|
+
if ([4015, 4009].includes(payload.code)) {
|
|
498
|
+
this.send({
|
|
499
|
+
guild_id: payload.guildId,
|
|
500
|
+
channel_id: this.voiceChannel,
|
|
501
|
+
self_mute: this.mute,
|
|
502
|
+
self_deaf: this.deaf,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
this.muthera.emit("socketClosed", player, payload);
|
|
507
|
+
this.pause(true);
|
|
508
|
+
this.muthera.emit("debug", this.guildId, "An error has occured.");
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
set(key, value) {
|
|
512
|
+
return (this.data[key] = value);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
get(key) {
|
|
516
|
+
return this.data[key];
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
send(data) {
|
|
520
|
+
this.muthera.send({ op: 4, d: data });
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
module.exports = { Player };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class Queue extends Array {
|
|
2
|
+
get size() {
|
|
3
|
+
return this.length;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
get first() {
|
|
7
|
+
return this.length ? this[0] : null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
add(track) {
|
|
11
|
+
this.push(track);
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
remove(index) {
|
|
16
|
+
if (index >= 0 && index < this.length) {
|
|
17
|
+
return this.splice(index, 1)[0];
|
|
18
|
+
} else {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"Index out of range. The number was too big or too small."
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
clear() {
|
|
26
|
+
this.length = 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
shuffle() {
|
|
30
|
+
for (let i = this.length - 1; i > 0; i--) {
|
|
31
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
32
|
+
[this[i], this[j]] = [this[j], this[i]];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { Queue };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
class Rest {
|
|
2
|
+
constructor(muthera, options) {
|
|
3
|
+
this.muthera = muthera;
|
|
4
|
+
this.url = `http${options.secure ? "s" : ""}://${options.host}:${options.port}`;
|
|
5
|
+
this.sessionId = options.sessionId;
|
|
6
|
+
this.password = options.password;
|
|
7
|
+
this.version = options.restVersion;
|
|
8
|
+
this.calls = 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
setSessionId(sessionId) {
|
|
12
|
+
this.sessionId = sessionId;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async makeRequest(method, endpoint, body = null) {
|
|
16
|
+
const headers = {
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
Authorization: this.password,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const requestOptions = {
|
|
22
|
+
method,
|
|
23
|
+
headers,
|
|
24
|
+
body: body ? JSON.stringify(body) : null,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const response = await fetch(this.url + endpoint, requestOptions);
|
|
28
|
+
|
|
29
|
+
this.calls++
|
|
30
|
+
|
|
31
|
+
if (response.statusCode === 204) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
return data;
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async getPlayers() {
|
|
44
|
+
return this.makeRequest("GET", `/v4/sessions/${this.sessionId}/players`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async updatePlayer(options) {
|
|
48
|
+
return this.makeRequest("PATCH", `/v4/sessions/${this.sessionId}/players/${options.guildId}?noReplace=false`, options.data).then((res) => {
|
|
49
|
+
this.muthera.emit("res", options.guildId, res);
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async destroyPlayer(guildId) {
|
|
54
|
+
return this.makeRequest("DELETE", `/v4/sessions/${this.sessionId}/players/${guildId}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async getTracks(identifier) {
|
|
58
|
+
return this.makeRequest("GET", `/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`).then((res) => {
|
|
59
|
+
this.muthera.emit("res", identifier, res);
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async decodeTrack(track, node) {
|
|
64
|
+
if (!node) node = this.leastUsedNodes[0];
|
|
65
|
+
return this.makeRequest(`GET`, `/v4/decodetrack?encodedTrack=${encodeURIComponent(track)}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async decodeTracks(tracks) {
|
|
69
|
+
return await this.makeRequest(`POST`, `/v4/decodetracks`, tracks);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async getStats() {
|
|
73
|
+
return this.makeRequest("GET", `/v4/stats`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async getInfo() {
|
|
77
|
+
return this.makeRequest("GET", `/v4/info`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async getRoutePlannerStatus() {
|
|
81
|
+
return await this.makeRequest(`GET`, `/v4/routeplanner/status`);
|
|
82
|
+
}
|
|
83
|
+
async getRoutePlannerAddress(address) {
|
|
84
|
+
return this.makeRequest(`POST`, `/v4/routeplanner/free/address`, { address });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async parseResponse(req) {
|
|
88
|
+
try {
|
|
89
|
+
this.muthera.emit("mutheraRaw", "Rest", await req.json());
|
|
90
|
+
return await req.json();
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { Rest };
|