poru 1.1.9 → 1.2.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/package.json +1 -1
- package/src/Node.js +105 -108
- package/src/Player.js +3 -6
- package/src/Poru.js +130 -147
- package/src/config.js +3 -0
- package/src/guild/DeezerTrack.js +61 -0
- package/src/platform/Apple.js +4 -2
- package/src/platform/Deezer.js +201 -0
- package/src/platform/Spotify.js +4 -6
- package/typings/index.d.ts +27 -48
- package/src/config.json +0 -3
package/package.json
CHANGED
package/src/Node.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
const WebSocket = require("ws");
|
|
2
|
-
const config = require("./config
|
|
2
|
+
const config = require("./config")
|
|
3
3
|
|
|
4
4
|
class Node {
|
|
5
5
|
constructor(manager,options,node) {
|
|
6
|
-
|
|
7
6
|
this.manager = manager
|
|
8
7
|
this.name= options.name || null;
|
|
9
8
|
this.host = options.host || "localhost"
|
|
10
9
|
this.port = options.port || 2333
|
|
11
|
-
this.url = `${options.secure ? 'wss' : 'ws'}://${options.host}:${options.port}`;
|
|
12
10
|
this.password = options.password ||"youshallnotpass"
|
|
13
11
|
this.secure = options.secure || false;
|
|
12
|
+
this.url = `${this.secure ? 'wss' : 'ws'}://${this.host}:${this.port}/`;
|
|
14
13
|
this.ws = null;
|
|
15
14
|
this.reconnectTime = node.reconnectTime || 5000;
|
|
16
15
|
this.resumeKey = node.resumeKey || null;
|
|
@@ -37,132 +36,130 @@ class Node {
|
|
|
37
36
|
};
|
|
38
37
|
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
connect() {
|
|
43
|
-
if (this.ws) this.ws.close();
|
|
44
|
-
const headers = {
|
|
45
|
-
Authorization: this.password,
|
|
46
|
-
"Num-Shards": this.manager.shards || 1,
|
|
47
|
-
"User-Id": this.manager.user,
|
|
48
|
-
"Client-Name": config.client
|
|
49
|
-
};
|
|
50
|
-
if (this.resumeKey) headers["Resume-Key"] = this.resumeKey;
|
|
51
|
-
this.ws = new WebSocket(`ws${this.secure ? "s" : ""}:${this.host}:${this.port}/`, { headers });
|
|
52
|
-
this.ws.on("open",this.#open.bind(this));
|
|
53
|
-
this.ws.on("error", this.#error.bind(this));
|
|
54
|
-
this.ws.on("message", this.#message.bind(this));
|
|
55
|
-
this.ws.on("close", this.#close.bind(this));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
#open(){
|
|
60
|
-
if (this.reconnectAttempt) {
|
|
61
|
-
clearTimeout(this.reconnectAttempt);
|
|
62
|
-
delete this.reconnectAttempt;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (this.resumeKey){
|
|
66
|
-
this.send({
|
|
67
|
-
op: "configureResuming",
|
|
68
|
-
key: (this.resumeKey).toString(),
|
|
69
|
-
timeout: this.resumeTimeout
|
|
70
|
-
});
|
|
71
|
-
this.manager.emit("debug",this.name,`[Web Socket] Resuming configured on Lavalink`)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this.manager.emit("nodeConnect", this);
|
|
75
|
-
this.isConnected = true;
|
|
76
|
-
this.manager.emit('debug', this.name, `[Web Socket] Connection ready ${this.url}`);
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
#message(payload) {
|
|
81
|
-
if (Array.isArray(payload)) payload = Buffer.concat(payload);
|
|
82
|
-
else if (payload instanceof ArrayBuffer) payload = Buffer.from(payload);
|
|
39
|
+
}
|
|
83
40
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
41
|
+
connect() {
|
|
42
|
+
if (this.ws) this.ws.close();
|
|
43
|
+
const headers = {
|
|
44
|
+
Authorization: this.password,
|
|
45
|
+
"Num-Shards": this.manager.shards || 1,
|
|
46
|
+
"User-Id": this.manager.user,
|
|
47
|
+
"Client-Name": config.clientName
|
|
48
|
+
};
|
|
49
|
+
if (this.resumeKey) headers["Resume-Key"] = this.resumeKey;
|
|
50
|
+
this.ws = new WebSocket(this.url, { headers });
|
|
51
|
+
this.ws.on("open",this.#open.bind(this));
|
|
52
|
+
this.ws.on("error", this.#error.bind(this));
|
|
53
|
+
this.ws.on("message", this.#message.bind(this));
|
|
54
|
+
this.ws.on("close", this.#close.bind(this));
|
|
88
55
|
}
|
|
89
|
-
const player = this.manager.players.get(packet.guildId);
|
|
90
|
-
if (packet.guildId && player) player.emit(packet.op, packet);
|
|
91
56
|
|
|
92
|
-
packet.node = this;
|
|
93
|
-
this.manager.emit("debug",this.name,`[Web Socket] Lavalink Node Update : ${packet.op} `)
|
|
94
|
-
this.manager.emit("raw", packet);
|
|
95
|
-
}
|
|
96
57
|
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
58
|
+
#open(){
|
|
59
|
+
if (this.reconnectAttempt) {
|
|
60
|
+
clearTimeout(this.reconnectAttempt);
|
|
61
|
+
delete this.reconnectAttempt;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (this.resumeKey){
|
|
65
|
+
this.send({
|
|
66
|
+
op: "configureResuming",
|
|
67
|
+
key: (this.resumeKey).toString(),
|
|
68
|
+
timeout: this.resumeTimeout
|
|
69
|
+
});
|
|
70
|
+
this.manager.emit("debug",this.name,`[Web Socket] Resuming configured on Lavalink`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.manager.emit("nodeConnect", this);
|
|
74
|
+
this.isConnected = true;
|
|
75
|
+
this.manager.emit('debug', this.name, `[Web Socket] Connection ready ${this.url}`);
|
|
101
76
|
|
|
102
|
-
return this.reconnect();
|
|
103
77
|
}
|
|
104
|
-
}
|
|
105
78
|
|
|
79
|
+
#message(payload) {
|
|
80
|
+
if (Array.isArray(payload)) payload = Buffer.concat(payload);
|
|
81
|
+
else if (payload instanceof ArrayBuffer) payload = Buffer.from(payload);
|
|
106
82
|
|
|
107
|
-
|
|
108
|
-
|
|
83
|
+
const packet = JSON.parse(payload);
|
|
84
|
+
if(!packet.op) return;
|
|
85
|
+
|
|
86
|
+
if (packet.op && packet.op === "stats") {
|
|
87
|
+
this.stats = { ...packet };
|
|
88
|
+
delete this.stats.op;
|
|
89
|
+
}
|
|
90
|
+
const player = this.manager.players.get(packet.guildId);
|
|
91
|
+
if (packet.guildId && player) player.emit(packet.op, packet);
|
|
92
|
+
|
|
93
|
+
packet.node = this;
|
|
94
|
+
this.manager.emit("debug",this.name,`[Web Socket] Lavalink Node Update : ${packet.op} `)
|
|
95
|
+
this.manager.emit("raw", packet);
|
|
96
|
+
}
|
|
109
97
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
98
|
+
#close(event) {
|
|
99
|
+
this.manager.emit("nodeDisconnect", event, this);
|
|
100
|
+
this.manager.emit("debug",this.name,`[Web Socket] Connection with Lavalink closed with Error code : ${event||"Unknown code"}`)
|
|
101
|
+
if (event !== 1000){
|
|
102
|
+
|
|
103
|
+
return this.reconnect();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
114
106
|
|
|
115
|
-
destroy(){
|
|
116
|
-
if(!this.isConnected) return;
|
|
117
107
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.ws.close(1000, "destroy");
|
|
121
|
-
this.ws.removeAllListeners();
|
|
122
|
-
this.ws = null;
|
|
123
|
-
this.reconnect = 1;
|
|
124
|
-
this.destroyed = true;
|
|
125
|
-
this.manager.nodes.delete(this.host)
|
|
126
|
-
this.manager.emit("nodeDestroy", this);
|
|
108
|
+
#error(event) {
|
|
109
|
+
if (!event) return "Unknown event";
|
|
127
110
|
|
|
111
|
+
this.manager.emit("debug",this.name,`[Web Socket] Connection for Lavalink node has error code: ${event.code}`)
|
|
112
|
+
this.manager.emit("nodeError", this, event);
|
|
113
|
+
return this.reconnect();
|
|
114
|
+
}
|
|
128
115
|
|
|
129
|
-
|
|
116
|
+
destroy(){
|
|
117
|
+
if(!this.isConnected) return;
|
|
130
118
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.
|
|
119
|
+
const players = this.manager.players.filter(p => p.node == this);
|
|
120
|
+
if (players.size) players.forEach(p => p.destroy());
|
|
121
|
+
this.ws.close(1000, "destroy");
|
|
134
122
|
this.ws.removeAllListeners();
|
|
135
123
|
this.ws = null;
|
|
136
|
-
this.
|
|
137
|
-
this.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
send(payload) {
|
|
142
|
-
this.ws.send(JSON.stringify(payload), (error) => {
|
|
143
|
-
if (error) return error;
|
|
144
|
-
return null;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
124
|
+
this.reconnect = 1;
|
|
125
|
+
this.destroyed = true;
|
|
126
|
+
this.manager.nodes.delete(this.host)
|
|
127
|
+
this.manager.emit("nodeDestroy", this);
|
|
147
128
|
|
|
148
129
|
|
|
149
|
-
|
|
150
|
-
get penalties(){
|
|
151
|
-
let penalties = 0;
|
|
152
|
-
if (!this.isConnected) return penalties;
|
|
153
|
-
penalties += this.stats.players;
|
|
154
|
-
penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10);
|
|
155
|
-
if (this.stats.frameStats) {
|
|
156
|
-
penalties += this.stats.frameStats.deficit;
|
|
157
|
-
penalties += this.stats.frameStats.nulled * 2;
|
|
158
130
|
}
|
|
159
|
-
return penalties;
|
|
160
|
-
}
|
|
161
131
|
|
|
132
|
+
reconnect() {
|
|
133
|
+
this.reconnectAttempt = setTimeout(() => {
|
|
134
|
+
this.isConnected = false;
|
|
135
|
+
this.ws.removeAllListeners();
|
|
136
|
+
this.ws = null;
|
|
137
|
+
this.manager.emit("nodeReconnect", this);
|
|
138
|
+
this.connect();
|
|
139
|
+
}, this.reconnectTime);
|
|
140
|
+
}
|
|
162
141
|
|
|
163
|
-
|
|
164
|
-
|
|
142
|
+
send(payload) {
|
|
143
|
+
const data = JSON.stringify(payload);
|
|
144
|
+
this.ws.send(data, (error) => {
|
|
145
|
+
if (error) return error;
|
|
146
|
+
return null;
|
|
147
|
+
});
|
|
148
|
+
this.manager.emit("raw", data, this.name)
|
|
149
|
+
}
|
|
165
150
|
|
|
151
|
+
get penalties(){
|
|
152
|
+
let penalties = 0;
|
|
153
|
+
if (!this.isConnected) return penalties;
|
|
154
|
+
penalties += this.stats.players;
|
|
155
|
+
penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10);
|
|
156
|
+
if (this.stats.frameStats) {
|
|
157
|
+
penalties += this.stats.frameStats.deficit;
|
|
158
|
+
penalties += this.stats.frameStats.nulled * 2;
|
|
159
|
+
}
|
|
160
|
+
return penalties;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
166
163
|
|
|
167
|
-
|
|
164
|
+
module.exports = Node;
|
|
168
165
|
|
package/src/Player.js
CHANGED
|
@@ -50,6 +50,7 @@ class Player extends EventEmitter {
|
|
|
50
50
|
this.manager.emit("playerUpdate", this, packet);
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
+
|
|
53
54
|
async play() {
|
|
54
55
|
|
|
55
56
|
if (!this.queue.length) {
|
|
@@ -72,7 +73,7 @@ class Player extends EventEmitter {
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
stop() {
|
|
76
77
|
|
|
77
78
|
this.position = 0;
|
|
78
79
|
this.isConnectd = false
|
|
@@ -182,9 +183,6 @@ class Player extends EventEmitter {
|
|
|
182
183
|
return this;
|
|
183
184
|
}
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
186
|
async disconnect() {
|
|
189
187
|
if (this.voiceChannel === null) return null;
|
|
190
188
|
this.pause(true);
|
|
@@ -221,7 +219,7 @@ class Player extends EventEmitter {
|
|
|
221
219
|
|
|
222
220
|
let response = await this.manager.resolve(data);
|
|
223
221
|
|
|
224
|
-
if (!response || !response.tracks || ["LOAD_FAILED", "NO_MATCHES"].includes(response.
|
|
222
|
+
if (!response || !response.tracks || ["LOAD_FAILED", "NO_MATCHES"].includes(response.loadType)) return this.stop();
|
|
225
223
|
|
|
226
224
|
let track = response.tracks[Math.floor(Math.random() * Math.floor(response.tracks.length))];
|
|
227
225
|
|
|
@@ -306,7 +304,6 @@ class Player extends EventEmitter {
|
|
|
306
304
|
return events[data.type] || events.default;
|
|
307
305
|
}
|
|
308
306
|
|
|
309
|
-
|
|
310
307
|
}
|
|
311
308
|
|
|
312
309
|
module.exports = Player;
|
package/src/Poru.js
CHANGED
|
@@ -3,29 +3,30 @@ const { fetch } = require('undici');
|
|
|
3
3
|
const Player = require("./Player");
|
|
4
4
|
const Node = require("./Node");
|
|
5
5
|
const Response = require("./guild/Response");
|
|
6
|
-
const config = require("./config.json")
|
|
7
6
|
const Spotify = require("./platform/Spotify")
|
|
8
7
|
const Apple = require("./platform/Apple")
|
|
9
|
-
|
|
8
|
+
const Deezer = require("./platform/Deezer")
|
|
10
9
|
class Poru extends EventEmitter {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
constructor(client, nodes, options = {}) {
|
|
11
|
+
super();
|
|
12
|
+
if (!client) throw new Error("[Poru Error] you did't provide a valid client");
|
|
13
|
+
if (!nodes) throw new Error("[Poru Error] you did't provide a lavalink nodes");
|
|
14
|
+
if (!options) throw new Error("[Poru Error] options must be provided!")
|
|
15
|
+
this.client = client;
|
|
16
|
+
this._nodes = nodes;
|
|
17
|
+
this.nodes = new Map();
|
|
18
|
+
this.players = new Map();
|
|
19
|
+
this.voiceStates = new Map();
|
|
20
|
+
this.voiceServers = new Map();
|
|
21
|
+
this.user = null;
|
|
22
|
+
this.options = options
|
|
23
|
+
this.shards = options.shards || 1;
|
|
24
|
+
this.sendData = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
//create a node and connect it with lavalink
|
|
29
30
|
addNode(options) {
|
|
30
31
|
const node = new Node(this, options, this.options);
|
|
31
32
|
if (options.name) {
|
|
@@ -72,27 +73,33 @@ class Poru extends EventEmitter {
|
|
|
72
73
|
const guild = client.guilds.cache.get(data.d.guild_id);
|
|
73
74
|
if (guild) guild.shard.send(data);
|
|
74
75
|
}
|
|
76
|
+
|
|
75
77
|
client.on("raw", async packet => {
|
|
76
78
|
await this.packetUpdate(packet);
|
|
77
79
|
})
|
|
78
|
-
|
|
80
|
+
|
|
79
81
|
this._nodes.forEach((node) => this.addNode(node));
|
|
80
82
|
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
this.spotify = new Spotify(this,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if (this.options.spotify && this.options.spotify.clientID && this.options.spotify.clientSecret) {
|
|
85
|
+
this.spotify = new Spotify(this, this.options)
|
|
86
|
+
}
|
|
87
|
+
if (this.options.apple) {
|
|
88
|
+
if (!this.options.apple.playlistLimit) {
|
|
89
|
+
throw new Error("[Poru Apple Music] playlistLimit must be provided")
|
|
90
|
+
}
|
|
91
|
+
this.apple = new Apple(this, this.options)
|
|
92
|
+
}
|
|
93
|
+
if (this.options.deezer) {
|
|
94
|
+
if (!this.options.deezer.playlistLimit) {
|
|
95
|
+
throw new Error("[Poru Deezer Music] playlistLimit must be provided")
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
this.deezer = new Deezer(this, this.options)
|
|
99
|
+
|
|
87
100
|
}
|
|
88
|
-
if(this.options.apple){
|
|
89
|
-
if(!this.options.apple.playlistLimit){
|
|
90
|
-
throw new Error("[Poru Apple Music] playlistLimit must be provided")
|
|
91
|
-
}
|
|
92
|
-
this.apple = new Apple(this,this.options)
|
|
93
|
-
}
|
|
94
101
|
console.log(`Thanks for using Poru`)
|
|
95
|
-
}
|
|
102
|
+
}
|
|
96
103
|
|
|
97
104
|
|
|
98
105
|
setServersUpdate(data) {
|
|
@@ -110,100 +117,93 @@ if(this.options.apple){
|
|
|
110
117
|
});
|
|
111
118
|
|
|
112
119
|
return true;
|
|
113
|
-
|
|
114
|
-
this.sendData({
|
|
115
|
-
op: 4,
|
|
116
|
-
d: {
|
|
117
|
-
guild_id: data.guild.id || data.guild,
|
|
118
|
-
channel_id: data.voiceChannel.id || data.voiceChannel,
|
|
119
|
-
self_mute: data.selfMute || false,
|
|
120
|
-
self_deaf: data.selfDeaf || true,
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
return this.#Player(data);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
init(client) {
|
|
127
|
-
this.user = client.user.id;
|
|
128
|
-
this.sendData = data => {
|
|
129
|
-
const guild = client.guilds.cache.get(data.d.guild_id);
|
|
130
|
-
if (guild) guild.shard.send(data);
|
|
131
|
-
};
|
|
132
|
-
client.on('raw', async packet => {
|
|
133
|
-
await this.#packetUpdate(packet);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
this._nodes.forEach(node => this.addNode(node));
|
|
137
|
-
|
|
138
|
-
if (this.options.spotify && this.options.spotify.clientID && this.options.spotify.clientSecret) {
|
|
139
|
-
this.spotify = new Spotify(this, {
|
|
140
|
-
clientID: this.options.clientID,
|
|
141
|
-
clientSecret: this.options.clientSecret,
|
|
142
|
-
playlistLimit: this.options.playlistLimit,
|
|
143
|
-
albumLimit: this.options.albumLimit,
|
|
144
|
-
artistLimit: this.options.artistLimit,
|
|
145
|
-
searchMarket: this.options.searchMarket,
|
|
146
|
-
});
|
|
147
120
|
}
|
|
148
|
-
this.voiceServers.delete(data.guild_id);
|
|
149
|
-
this.voiceStates.delete(data.guild_id);
|
|
150
|
-
}
|
|
151
121
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
122
|
+
setStateUpdate(data) {
|
|
123
|
+
if (data.user_id !== this.user) return;
|
|
124
|
+
if (data.channel_id) {
|
|
125
|
+
const guild = data.guild_id;
|
|
156
126
|
|
|
157
|
-
|
|
158
|
-
|
|
127
|
+
this.voiceStates.set(data.guild_id, data);
|
|
128
|
+
const server = this.voiceServers.get(guild);
|
|
129
|
+
const state = this.voiceStates.get(guild);
|
|
130
|
+
if (!server) return false;
|
|
131
|
+
const player = this.players.get(guild);
|
|
132
|
+
if (!player) return false;
|
|
133
|
+
|
|
134
|
+
player.connect({
|
|
135
|
+
sessionId: state ? state.session_id : player.voiceUpdateState.sessionId,
|
|
136
|
+
event: server,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
this.voiceServers.delete(data.guild_id);
|
|
142
|
+
this.voiceStates.delete(data.guild_id);
|
|
159
143
|
}
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
|
|
145
|
+
packetUpdate(packet) {
|
|
146
|
+
if (!['VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE'].includes(packet.t)) return;
|
|
147
|
+
const player = this.players.get(packet.d.guild_id);
|
|
148
|
+
if (!player) return;
|
|
149
|
+
|
|
150
|
+
if (packet.t === "VOICE_SERVER_UPDATE") {
|
|
151
|
+
this.setServersUpdate(packet.d);
|
|
152
|
+
}
|
|
153
|
+
if (packet.t === "VOICE_STATE_UPDATE") {
|
|
154
|
+
this.setStateUpdate(packet.d);
|
|
155
|
+
}
|
|
162
156
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
get leastUsedNodes() {
|
|
161
|
+
return [...this.nodes.values()]
|
|
162
|
+
.filter((node) => node.isConnected)
|
|
163
|
+
.sort((a, b) => {
|
|
164
|
+
const aLoad = a.stats.cpu ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100 : 0;
|
|
165
|
+
const bLoad = b.stats.cpu ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100 : 0;
|
|
166
|
+
return aLoad - bLoad;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#Player(data) {
|
|
171
|
+
const guild = data.guild.id || data.guild;
|
|
172
|
+
const Nodes = this.nodes.get(guild);
|
|
173
|
+
if (Nodes) return Nodes;
|
|
174
|
+
if (this.leastUsedNodes.length === 0) throw new Error("[Poru Error] No nodes are avaliable");
|
|
175
|
+
const node = this.nodes.get(this.leastUsedNodes[0].name
|
|
176
|
+
|| this.leastUsedNodes[0].host);
|
|
177
|
+
if (!node) throw new Error("[Poru Error] No nodes are avalible");
|
|
178
|
+
|
|
179
|
+
// eslint-disable-next-line new-cap
|
|
180
|
+
const player = new Player(this, node, data);
|
|
181
|
+
this.players.set(guild, player);
|
|
182
|
+
player.connect()
|
|
183
|
+
return player;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
189
188
|
|
|
190
189
|
async resolve(track, source) {
|
|
191
|
-
|
|
190
|
+
|
|
192
191
|
const node = this.leastUsedNodes[0];
|
|
193
192
|
if (!node) throw new Error("No nodes are available.");
|
|
194
|
-
if(this.spotify &&
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if(this.apple && this.apple.check(track)){
|
|
193
|
+
if (this.spotify && this.spotify.check(track)) {
|
|
194
|
+
return await this.spotify.resolve(track);
|
|
195
|
+
}else if (this.apple && this.apple.check(track)) {
|
|
199
196
|
return await this.apple.resolve(track);
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
}else if (this.deezer && this.deezer.check(track)) {
|
|
198
|
+
return await this.deezer.resolve(track);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
202
|
|
|
203
203
|
const regex = /^https?:\/\//;
|
|
204
204
|
if (!regex.test(track)) {
|
|
205
205
|
// eslint-disable-next-line no-param-reassign
|
|
206
|
-
track = `${source || "
|
|
206
|
+
track = `${source || "ytsearch"}:${track}`;
|
|
207
207
|
}
|
|
208
208
|
const result = await this.#fetch(node, "loadtracks", `identifier=${encodeURIComponent(track)}`);
|
|
209
209
|
|
|
@@ -219,40 +219,23 @@ if(this.options.apple){
|
|
|
219
219
|
if (result.status === 500) return null;
|
|
220
220
|
return result;
|
|
221
221
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
|
|
223
|
+
#fetch(node, endpoint, param) {
|
|
224
|
+
return fetch(`http${node.secure ? "s" : ""}://${node.host}:${node.port}/${endpoint}?${param}`, {
|
|
225
|
+
headers: {
|
|
226
|
+
Authorization: node.password,
|
|
227
|
+
|
|
228
|
+
},
|
|
229
|
+
})
|
|
230
|
+
.then((r) => r.json())
|
|
231
|
+
.catch((e) => {
|
|
232
|
+
throw new Error(`[Poru Error] Failed to fetch from the lavalink.\n error: ${e}`);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
get(guildId) {
|
|
237
|
+
return this.players.get(guildId);
|
|
226
238
|
}
|
|
227
|
-
const result = await this.#fetch(node, 'loadtracks', `identifier=${encodeURIComponent(track)}`);
|
|
228
|
-
|
|
229
|
-
if (!result) throw new Error('[Poru Error] No tracks found.');
|
|
230
|
-
return new Response(result);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async decodeTrack(track) {
|
|
234
|
-
const node = this.leastUsedNodes[0];
|
|
235
|
-
if (!node) throw new Error('No nodes are available.');
|
|
236
|
-
const result = await this.#fetch(node, 'decodetrack', `track=${track}`);
|
|
237
|
-
if (result.status === 500) return null;
|
|
238
|
-
return result;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
#fetch(node, endpoint, param) {
|
|
242
|
-
return fetch(`http${node.secure ? 's' : ''}://${node.host}:${node.port}/${endpoint}?${param}`, {
|
|
243
|
-
headers: {
|
|
244
|
-
Authorization: node.password,
|
|
245
|
-
},
|
|
246
|
-
})
|
|
247
|
-
.then(r => r.json())
|
|
248
|
-
.catch(e => {
|
|
249
|
-
throw new Error(`[Poru Error] Failed to fetch from the lavalink.\n error: ${e}`);
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
get(guildId) {
|
|
254
|
-
return this.players.get(guildId);
|
|
255
|
-
}
|
|
256
239
|
}
|
|
257
240
|
|
|
258
|
-
module.exports = Poru
|
|
241
|
+
module.exports = Poru
|
package/src/config.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2
|
+
class DeezerTrack {
|
|
3
|
+
constructor(data) {
|
|
4
|
+
this.track = data.track
|
|
5
|
+
this.info = {
|
|
6
|
+
identifier: null,
|
|
7
|
+
isSeekable: data.info.isSeekable,
|
|
8
|
+
author: data.info.author,
|
|
9
|
+
length: data.info.length,
|
|
10
|
+
isStream: data.info.isStream,
|
|
11
|
+
sourceName: data.info.sourceName,
|
|
12
|
+
title: data.info.title,
|
|
13
|
+
uri: data.info.uri,
|
|
14
|
+
image: data.image || null
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async resolve(manager) {
|
|
20
|
+
|
|
21
|
+
const query = [this.info.author, this.info.title].filter((x) => !!x).join(' - ');
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
const result = await manager.resolve(query);
|
|
25
|
+
if (!result || !result.tracks.length) return;
|
|
26
|
+
|
|
27
|
+
if (this.info.author) {
|
|
28
|
+
const author = [this.info.author, `${this.info.author} - Topic`];
|
|
29
|
+
const officialAudio = result.tracks.find(
|
|
30
|
+
(track) =>
|
|
31
|
+
author.some((name) => new RegExp(`^${escapeRegExp(name)}$`, 'i').test(track.info.author)) ||
|
|
32
|
+
new RegExp(`^${escapeRegExp(this.info.title)}$`, 'i').test(track.info.title),
|
|
33
|
+
);
|
|
34
|
+
if (officialAudio) {
|
|
35
|
+
this.info.identifier = officialAudio.info.identifier
|
|
36
|
+
this.track = officialAudio.track;
|
|
37
|
+
this.length = officialAudio.info.length
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (this.info.length) {
|
|
42
|
+
const sameDuration = result.tracks.find(
|
|
43
|
+
(track) =>
|
|
44
|
+
track.info.length >= (this.info.length ? this.length : 0) - 2000 &&
|
|
45
|
+
track.info.length <= (this.info.length ? this.length : 0) + 2000,
|
|
46
|
+
);
|
|
47
|
+
if (sameDuration) {
|
|
48
|
+
this.info.identifier = sameDuration.info.identifier
|
|
49
|
+
this.track = sameDuration.track;
|
|
50
|
+
this.length = officialAudio.info.length
|
|
51
|
+
return this
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
this.info.identifier = result.tracks[0].info.identifier
|
|
55
|
+
this.track = result.tracks[0].track;
|
|
56
|
+
this.length = officialAudio.info.length
|
|
57
|
+
return this
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = DeezerTrack;
|
package/src/platform/Apple.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {fetch} = require("undici")
|
|
2
2
|
const Track = require("../guild/Track")
|
|
3
3
|
const cheerio = require("cheerio")
|
|
4
4
|
|
|
@@ -8,9 +8,10 @@ class Apple {
|
|
|
8
8
|
this.baseURL = /(?:https:\/\/music\.apple\.com\/)(?:.+)?(artist|album|music-video|playlist)\/([\w\-\.]+(\/)+[\w\-\.]+|[^&]+)\/([\w\-\.]+(\/)+[\w\-\.]+|[^&]+)/;
|
|
9
9
|
this.applePattern = /(?:https:\/\/music\.apple\.com\/)(?:\w{2}\/)?(track|album|playlist)/g;
|
|
10
10
|
this.REGEX = /(?:https:\/\/music\.apple\.com\/)(?:\w{2}\/)?(track|album|playlist)/g;
|
|
11
|
-
this.playlistLimit = options.playlistLimit || null;
|
|
11
|
+
this.playlistLimit = options.apple.playlistLimit || null;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
|
|
14
15
|
check(url) {
|
|
15
16
|
return this.baseURL.test(url);
|
|
16
17
|
}
|
|
@@ -232,4 +233,5 @@ class Apple {
|
|
|
232
233
|
|
|
233
234
|
|
|
234
235
|
}
|
|
236
|
+
|
|
235
237
|
module.exports = Apple
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
const { fetch } = require('undici');
|
|
2
|
+
const DeezerTrack = require("../guild/DeezerTrack")
|
|
3
|
+
|
|
4
|
+
class Deezer {
|
|
5
|
+
constructor(manager, options) {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
this.manager = manager;
|
|
9
|
+
this.baseURL = 'https://api.deezer.com';
|
|
10
|
+
this.REGEX = /^(?:https?:\/\/|)?(?:www\.)?deezer\.com\/(?:\w{2}\/)?(track|album|playlist|artist)\/(\d+)/
|
|
11
|
+
this.playlistLimit = options.deezer.playlistLimit || null;
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
check(url) {
|
|
17
|
+
return this.REGEX.test(url);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async requestData(endpoint) {
|
|
21
|
+
const req = await fetch(`${this.baseURL}/${endpoint}`, {
|
|
22
|
+
});
|
|
23
|
+
const data = await req.json();
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async resolve(url) {
|
|
29
|
+
const [, type, id] = this.REGEX.exec(url) ?? [];
|
|
30
|
+
switch (type) {
|
|
31
|
+
case 'playlist': {
|
|
32
|
+
return this.fetchPlaylist(id);
|
|
33
|
+
}
|
|
34
|
+
case 'track': {
|
|
35
|
+
return this.fetchTrack(id);
|
|
36
|
+
}
|
|
37
|
+
case 'album': {
|
|
38
|
+
return this.fetchAlbum(id);
|
|
39
|
+
}
|
|
40
|
+
case 'artist': {
|
|
41
|
+
return this.fetchArtist(id);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async fetchPlaylist(id) {
|
|
52
|
+
try {
|
|
53
|
+
const playlist = await this.requestData(`/playlist/${id}`);
|
|
54
|
+
const unresolvedPlaylistTracks = await Promise.all(playlist.tracks.data.map(x => this.buildUnresolved(x)));
|
|
55
|
+
return this.buildResponse('PLAYLIST_LOADED', unresolvedPlaylistTracks, playlist.name);
|
|
56
|
+
|
|
57
|
+
} catch (e) {
|
|
58
|
+
return this.buildResponse(
|
|
59
|
+
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
|
|
60
|
+
[],
|
|
61
|
+
undefined,
|
|
62
|
+
e.body?.error.message ?? e.message,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async fetchAlbum(id) {
|
|
69
|
+
try {
|
|
70
|
+
const album = await this.requestData(`/album/${id}`)
|
|
71
|
+
|
|
72
|
+
const unresolvedAlbumTracks = await Promise.all(playlist.tracks.data.map(x => this.buildUnresolved(x)));
|
|
73
|
+
|
|
74
|
+
return this.buildResponse('PLAYLIST_LOADED', unresolvedAlbumTracks, album.name);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
return this.buildResponse(
|
|
77
|
+
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
|
|
78
|
+
[],
|
|
79
|
+
undefined,
|
|
80
|
+
e.body?.error.message ?? e.message,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async fetchTrack(id) {
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const track = await this.requestData(`/track/${id}`)
|
|
90
|
+
|
|
91
|
+
const unresolvedTrack = await Promise.all(this.buildUnresolved(track));
|
|
92
|
+
return this.buildResponse('TRACK_LOADED', [unresolvedTrack]);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return this.buildResponse(
|
|
95
|
+
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
|
|
96
|
+
[],
|
|
97
|
+
undefined,
|
|
98
|
+
e.body?.error.message ?? e.message,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async fetchArtist(id) {
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const artist = await this.requestData(`/artist/${id}/top`);
|
|
108
|
+
await this.fetchArtistTracks(artist)
|
|
109
|
+
const unresolvedArtistTracks = await Promise.all(artist.data.map(x => this.buildUnresolved(x)
|
|
110
|
+
));
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
return this.buildResponse('PLAYLIST_LOADED', unresolvedArtistTracks, artist.name);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
return this.buildResponse(
|
|
117
|
+
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
|
|
118
|
+
[],
|
|
119
|
+
undefined,
|
|
120
|
+
e.body?.error.message ?? e.message,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async fetchArtistTracks(deezerArtist) {
|
|
127
|
+
let nextPage = deezerArtist.next;
|
|
128
|
+
let pageLoaded = 1;
|
|
129
|
+
while (nextPage) {
|
|
130
|
+
if (!nextPage) break;
|
|
131
|
+
const req = await fetch(nextPage)
|
|
132
|
+
const json = await req.json()
|
|
133
|
+
|
|
134
|
+
deezerArtist.data.push(...json.data);
|
|
135
|
+
|
|
136
|
+
nextPage = json.next;
|
|
137
|
+
pageLoaded++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async fetch(query) {
|
|
142
|
+
try {
|
|
143
|
+
if (this.check(query)) return this.resolve(query)
|
|
144
|
+
let tracks = await this.requestData(`/search?q="${query}"`)
|
|
145
|
+
|
|
146
|
+
const unresolvedTrack = await Promise.all(this.buildUnresolved(tracks.data[0]));
|
|
147
|
+
return this.buildResponse('TRACK_LOADED', [unresolvedTrack]);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return this.buildResponse(
|
|
150
|
+
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
|
|
151
|
+
[],
|
|
152
|
+
undefined,
|
|
153
|
+
e.body?.error.message ?? e.message,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
async buildUnresolved(track) {
|
|
162
|
+
if (!track) throw new ReferenceError('The Deezer track object was not provided');
|
|
163
|
+
|
|
164
|
+
return new DeezerTrack({
|
|
165
|
+
track: '',
|
|
166
|
+
info: {
|
|
167
|
+
sourceName: 'deezer',
|
|
168
|
+
identifier: track.id,
|
|
169
|
+
isSeekable: true,
|
|
170
|
+
author: track.artist ? track.artist.name : 'Unknown',
|
|
171
|
+
length: track.duration,
|
|
172
|
+
isStream: false,
|
|
173
|
+
title: track.title,
|
|
174
|
+
uri: track.link,
|
|
175
|
+
image: track.album.cover_medium
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
compareValue(value) {
|
|
182
|
+
return typeof value !== 'undefined' ? value !== null : typeof value !== 'undefined';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
buildResponse(loadType, tracks, playlistName, exceptionMsg) {
|
|
186
|
+
return Object.assign(
|
|
187
|
+
{
|
|
188
|
+
loadType,
|
|
189
|
+
tracks,
|
|
190
|
+
playlistInfo: playlistName ? { name: playlistName } : {},
|
|
191
|
+
},
|
|
192
|
+
exceptionMsg ? { exception: { message: exceptionMsg, severity: 'COMMON' } } : {},
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = Deezer;
|
package/src/platform/Spotify.js
CHANGED
|
@@ -78,9 +78,7 @@ class Spotify {
|
|
|
78
78
|
return this.fetchArtist(id);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
return this.manager.resolve(url);
|
|
83
|
-
}
|
|
81
|
+
|
|
84
82
|
}
|
|
85
83
|
}
|
|
86
84
|
|
|
@@ -90,7 +88,7 @@ class Spotify {
|
|
|
90
88
|
await this.fetchPlaylistTracks(playlist);
|
|
91
89
|
|
|
92
90
|
const limitedTracks = this.playlistLimit
|
|
93
|
-
? playlist.tracks.items.slice(0, this.playlistLimit *
|
|
91
|
+
? playlist.tracks.items.slice(0, this.playlistLimit * 100)
|
|
94
92
|
: playlist.tracks.items;
|
|
95
93
|
|
|
96
94
|
const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x.track)));
|
|
@@ -110,7 +108,7 @@ class Spotify {
|
|
|
110
108
|
try {
|
|
111
109
|
const album = await this.requestData(`/albums/${id}`);
|
|
112
110
|
|
|
113
|
-
const limitedTracks = this.albumLimit ? album.tracks.items.slice(0, this.albumLimit *
|
|
111
|
+
const limitedTracks = this.albumLimit ? album.tracks.items.slice(0, this.albumLimit * 100) : album.tracks.items;
|
|
114
112
|
|
|
115
113
|
const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
|
|
116
114
|
return this.buildResponse('PLAYLIST_LOADED', unresolvedPlaylistTracks, album.name);
|
|
@@ -130,7 +128,7 @@ class Spotify {
|
|
|
130
128
|
|
|
131
129
|
const data = await this.requestData(`/artists/${id}/top-tracks?market=${this.searchMarket ?? 'US'}`);
|
|
132
130
|
|
|
133
|
-
const limitedTracks = this.artistLimit ? data.tracks.slice(0, this.artistLimit *
|
|
131
|
+
const limitedTracks = this.artistLimit ? data.tracks.slice(0, this.artistLimit * 100) : data.tracks;
|
|
134
132
|
|
|
135
133
|
const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
|
|
136
134
|
|
package/typings/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventEmitter } from "ws";
|
|
1
|
+
import { EventEmitter, WebSocket } from "ws";
|
|
2
2
|
|
|
3
3
|
declare module'Poru' {
|
|
4
4
|
|
|
@@ -56,48 +56,45 @@ export class Node {
|
|
|
56
56
|
constructor(manager:typeof EventEmitter|any,options:object,node:object)
|
|
57
57
|
|
|
58
58
|
public manager: EventEmitter
|
|
59
|
-
public name:
|
|
60
|
-
public host:
|
|
61
|
-
public port :
|
|
62
|
-
public url :
|
|
63
|
-
public password:
|
|
64
|
-
public secure:
|
|
65
|
-
public ws
|
|
66
|
-
public reconnectTime :
|
|
67
|
-
public resumeKey:
|
|
68
|
-
public resumeTimeout
|
|
69
|
-
public reconnectAttempt:
|
|
70
|
-
public reconnects:
|
|
71
|
-
public isConnected:
|
|
72
|
-
public destroyed:
|
|
59
|
+
public name: string
|
|
60
|
+
public host: string
|
|
61
|
+
public port : number
|
|
62
|
+
public url : string
|
|
63
|
+
public password: string
|
|
64
|
+
public secure: boolean
|
|
65
|
+
public ws: WebSocket
|
|
66
|
+
public reconnectTime : number
|
|
67
|
+
public resumeKey:string|number;
|
|
68
|
+
public resumeTimeout: number
|
|
69
|
+
public reconnectAttempt:number;
|
|
70
|
+
public reconnects:number;
|
|
71
|
+
public isConnected:boolean;
|
|
72
|
+
public destroyed:boolean;
|
|
73
73
|
public stats:Object
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
connect():void
|
|
77
77
|
|
|
78
|
-
destroy()
|
|
78
|
+
destroy(): void
|
|
79
79
|
|
|
80
|
-
reconnect()
|
|
80
|
+
reconnect(): void
|
|
81
81
|
|
|
82
|
-
send(playload:
|
|
82
|
+
send(playload:Object): void | Object | String
|
|
83
83
|
|
|
84
84
|
get penalties():Number
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
86
|
}
|
|
89
87
|
|
|
90
88
|
|
|
91
89
|
export class Player extends EventEmitter {
|
|
92
|
-
constructor(manager:EventEmitter,node:Map
|
|
93
|
-
|
|
90
|
+
constructor(manager:EventEmitter,node:Map<any, any>|Object, options:Object)
|
|
94
91
|
|
|
95
92
|
|
|
96
93
|
public manager:EventEmitter
|
|
97
94
|
|
|
98
|
-
public queue:Array |any
|
|
95
|
+
public queue:Array<any> |any
|
|
99
96
|
|
|
100
|
-
public node: Map
|
|
97
|
+
public node: Map<any, any>|Object|Any;
|
|
101
98
|
|
|
102
99
|
public filters: any
|
|
103
100
|
|
|
@@ -107,15 +104,15 @@ export class Player extends EventEmitter {
|
|
|
107
104
|
|
|
108
105
|
public textChannel:any;
|
|
109
106
|
|
|
110
|
-
public
|
|
107
|
+
public isConnected: boolean;
|
|
111
108
|
|
|
112
|
-
public isPlaying:
|
|
109
|
+
public isPlaying:boolean;
|
|
113
110
|
|
|
114
|
-
public isPause:
|
|
111
|
+
public isPause:boolean;
|
|
115
112
|
|
|
116
|
-
public trackRepeat:
|
|
113
|
+
public trackRepeat:boolean;
|
|
117
114
|
|
|
118
|
-
public queueRepeat:
|
|
115
|
+
public queueRepeat:boolean;
|
|
119
116
|
|
|
120
117
|
public loop:Number;
|
|
121
118
|
|
|
@@ -127,9 +124,7 @@ export class Player extends EventEmitter {
|
|
|
127
124
|
|
|
128
125
|
public previousTrack:Object;
|
|
129
126
|
|
|
130
|
-
public voiceUpdateState
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
public voiceUpdateState:any;
|
|
133
128
|
|
|
134
129
|
|
|
135
130
|
play()
|
|
@@ -158,24 +153,8 @@ export class Player extends EventEmitter {
|
|
|
158
153
|
|
|
159
154
|
disconnect()
|
|
160
155
|
|
|
161
|
-
|
|
162
156
|
destroy()
|
|
163
157
|
|
|
164
158
|
autoplay(toggle:Boolean)
|
|
165
159
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
160
|
}
|
package/src/config.json
DELETED