aqualink 2.9.13 â 2.10.0
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/README.md +94 -58
- package/build/handlers/autoplay.js +39 -44
- package/build/structures/Aqua.js +437 -468
- package/build/structures/Connection.js +91 -88
- package/build/structures/Filters.js +178 -167
- package/build/structures/Node.js +99 -96
- package/build/structures/Player.js +275 -296
- package/build/structures/Rest.js +265 -146
- package/build/structures/Track.js +51 -126
- package/package.json +17 -2
package/README.md
CHANGED
|
@@ -87,67 +87,65 @@
|
|
|
87
87
|
|
|
88
88
|
## đģ Quick Start
|
|
89
89
|
|
|
90
|
-
```
|
|
91
|
-
npm install aqualink
|
|
92
|
-
|
|
93
|
-
// If you're using Module, use this:
|
|
94
|
-
// import { createRequire } from 'module';
|
|
95
|
-
// const require = createRequire(import.meta.url);
|
|
96
|
-
|
|
97
|
-
//const { Aqua } = require('aqualink');
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
```bash
|
|
91
|
+
npm install aqualink discord.js
|
|
92
|
+
```
|
|
100
93
|
|
|
94
|
+
```javascript
|
|
101
95
|
const { Aqua } = require("aqualink");
|
|
102
|
-
const { Client,
|
|
96
|
+
const { Client, GatewayIntentBits, Events } = require("discord.js");
|
|
103
97
|
|
|
104
98
|
const client = new Client({
|
|
105
99
|
intents: [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
100
|
+
GatewayIntentBits.Guilds,
|
|
101
|
+
GatewayIntentBits.GuildMembers,
|
|
102
|
+
GatewayIntentBits.GuildMessages,
|
|
103
|
+
GatewayIntentBits.MessageContent,
|
|
104
|
+
GatewayIntentBits.GuildVoiceStates
|
|
111
105
|
]
|
|
112
106
|
});
|
|
113
107
|
|
|
114
108
|
const nodes = [
|
|
115
109
|
{
|
|
116
110
|
host: "127.0.0.1",
|
|
117
|
-
password: "
|
|
118
|
-
port:
|
|
111
|
+
password: "your_password",
|
|
112
|
+
port: 2333,
|
|
119
113
|
secure: false,
|
|
120
|
-
name: "
|
|
114
|
+
name: "main-node"
|
|
121
115
|
}
|
|
122
116
|
];
|
|
123
117
|
|
|
124
|
-
const aqua = Aqua(client, nodes, {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
const aqua = new Aqua(client, nodes, {
|
|
119
|
+
defaultSearchPlatform: "ytsearch",
|
|
120
|
+
restVersion: "v4",
|
|
121
|
+
autoResume: true,
|
|
122
|
+
infiniteReconnects: true,
|
|
123
|
+
autoplayPlatform: ['spsearch', 'ytsearch', 'scsearch'],
|
|
124
|
+
nodeResolver: 'LeastLoad'
|
|
129
125
|
});
|
|
130
126
|
|
|
131
127
|
client.aqua = aqua;
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
client.once("ready", () => {
|
|
129
|
+
client.once(Events.Ready, () => {
|
|
135
130
|
client.aqua.init(client.user.id);
|
|
136
|
-
console.log(
|
|
131
|
+
console.log(`Logged in as ${client.user.tag}`);
|
|
137
132
|
});
|
|
138
133
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (![GatewayDispatchEvents.VoiceStateUpdate, GatewayDispatchEvents.VoiceServerUpdate,].includes(d.t)) return;
|
|
134
|
+
client.on(Events.Raw, (d) => {
|
|
135
|
+
if (![Events.VoiceStateUpdate, Events.VoiceServerUpdate].includes(d.t)) return;
|
|
142
136
|
client.aqua.updateVoiceState(d);
|
|
143
137
|
});
|
|
144
138
|
|
|
145
|
-
client.on(
|
|
146
|
-
if (message.author.bot) return;
|
|
139
|
+
client.on(Events.MessageCreate, async (message) => {
|
|
140
|
+
if (message.author.bot || !message.content.startsWith("!play")) return;
|
|
147
141
|
|
|
148
|
-
|
|
142
|
+
const query = message.content.slice(6).trim();
|
|
143
|
+
if (!query) return message.channel.send("Please provide a song to play.");
|
|
149
144
|
|
|
150
|
-
|
|
145
|
+
// Check if user is in a voice channel
|
|
146
|
+
if (!message.member.voice.channel) {
|
|
147
|
+
return message.channel.send("You need to be in a voice channel to play music!");
|
|
148
|
+
}
|
|
151
149
|
|
|
152
150
|
const player = client.aqua.createConnection({
|
|
153
151
|
guildId: message.guild.id,
|
|
@@ -156,38 +154,76 @@ client.on("messageCreate", async (message) => {
|
|
|
156
154
|
deaf: true,
|
|
157
155
|
});
|
|
158
156
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
157
|
+
try {
|
|
158
|
+
const resolve = await client.aqua.resolve({ query, requester: message.member });
|
|
159
|
+
const { loadType, tracks, playlistInfo } = resolve;
|
|
160
|
+
|
|
161
|
+
if (loadType === 'playlist') {
|
|
162
|
+
for (const track of tracks) {
|
|
163
|
+
player.queue.add(track);
|
|
164
|
+
}
|
|
165
|
+
message.channel.send(`Added ${tracks.length} songs from ${playlistInfo.name}.`);
|
|
166
|
+
} else if (loadType === 'search' || loadType === 'track') {
|
|
167
|
+
const track = tracks[0];
|
|
168
|
+
player.queue.add(track);
|
|
169
|
+
message.channel.send(`Added **${track.title}** to the queue.`);
|
|
170
|
+
} else {
|
|
171
|
+
return message.channel.send("No results found.");
|
|
165
172
|
}
|
|
166
|
-
if (!player.playing && !player.paused) return player.play();
|
|
167
|
-
|
|
168
|
-
} else if (resolve.loadType === 'search' || resolve.loadType === 'track') {
|
|
169
|
-
const track = resolve.tracks.shift();
|
|
170
|
-
track.info.requester = message.member;
|
|
171
173
|
|
|
172
|
-
player.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
} else {
|
|
179
|
-
return message.channel.send(`There were no results found for your query.`);
|
|
174
|
+
if (!player.playing && !player.paused) {
|
|
175
|
+
player.play();
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error("Playback error:", error);
|
|
179
|
+
message.channel.send("An error occurred while trying to play the song.");
|
|
180
180
|
}
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
client.aqua.on("nodeConnect", (node) => {
|
|
184
184
|
console.log(`Node connected: ${node.name}`);
|
|
185
185
|
});
|
|
186
|
+
|
|
186
187
|
client.aqua.on("nodeError", (node, error) => {
|
|
187
188
|
console.log(`Node "${node.name}" encountered an error: ${error.message}.`);
|
|
188
189
|
});
|
|
189
190
|
|
|
190
|
-
client.
|
|
191
|
+
client.aqua.on('trackStart', (player, track) => {
|
|
192
|
+
const channel = client.channels.cache.get(player.textChannel);
|
|
193
|
+
if (channel) channel.send(`Now playing: **${track.title}**`);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
client.aqua.on('queueEnd', (player) => {
|
|
197
|
+
const channel = client.channels.cache.get(player.textChannel);
|
|
198
|
+
if (channel) channel.send('The queue has ended.');
|
|
199
|
+
player.destroy();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
client.login("YOUR_DISCORD_BOT_TOKEN");
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Additional Commands You Can Add:
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
client.on(Events.MessageCreate, async (message) => {
|
|
209
|
+
if (message.content === "!skip") {
|
|
210
|
+
const player = client.aqua.players.get(message.guild.id);
|
|
211
|
+
if (player) {
|
|
212
|
+
player.skip();
|
|
213
|
+
message.channel.send("âī¸ Skipped current track!");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
client.on(Events.MessageCreate, async (message) => {
|
|
219
|
+
if (message.content === "!stop") {
|
|
220
|
+
const player = client.aqua.players.get(message.guild.id);
|
|
221
|
+
if (player) {
|
|
222
|
+
player.destroy();
|
|
223
|
+
message.channel.send("âšī¸ Stopped playback and cleared queue!");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
191
227
|
```
|
|
192
228
|
|
|
193
229
|
## đ Featured Projects
|
|
@@ -223,7 +259,7 @@ client.login("Yourtokenhere");
|
|
|
223
259
|
|
|
224
260
|
For detailed usage, API references, and examples, check out our official documentation:
|
|
225
261
|
|
|
226
|
-
[](https://
|
|
262
|
+
[](https://roddynnn.github.io/docs/)
|
|
227
263
|
|
|
228
264
|
đ **Get Started Quickly**
|
|
229
265
|
- Installation guide
|
|
@@ -231,7 +267,7 @@ For detailed usage, API references, and examples, check out our official documen
|
|
|
231
267
|
- Advanced features
|
|
232
268
|
- Troubleshooting
|
|
233
269
|
|
|
234
|
-
đ Visit: **[Aqualink Docs](https://
|
|
270
|
+
đ Visit: **[Aqualink Docs](https://roddynnn.github.io/docs)**
|
|
235
271
|
|
|
236
272
|
## đ Premium Bots Using Aqualink
|
|
237
273
|
|
|
@@ -290,7 +326,7 @@ For detailed usage, API references, and examples, check out our official documen
|
|
|
290
326
|
<a href="https://github.com/pomicee">
|
|
291
327
|
<img src="https://avatars.githubusercontent.com/u/134554554?v=4?s=100" width="100px;" alt="pomicee"/>
|
|
292
328
|
<br />
|
|
293
|
-
<sub><b>
|
|
329
|
+
<sub><b>asynico</b></sub>
|
|
294
330
|
</a>
|
|
295
331
|
<br />
|
|
296
332
|
<a href="#code-pomicee" title="Code">đģ</a>
|
|
@@ -313,7 +349,7 @@ For detailed usage, API references, and examples, check out our official documen
|
|
|
313
349
|
<sub><b>SoulDevs</b></sub>
|
|
314
350
|
</a>
|
|
315
351
|
<br />
|
|
316
|
-
<a href="#code-SoulDevs title="Code">đģ</a>
|
|
352
|
+
<a href="#code-SoulDevs" title="Code">đģ</a>
|
|
317
353
|
</td>
|
|
318
354
|
</tr>
|
|
319
355
|
</tbody>
|
|
@@ -9,7 +9,6 @@ const agent = new https.Agent({
|
|
|
9
9
|
freeSocketTimeout: 4000
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
const TOTP_SECRET = Buffer.from("5507145853487499592248630329347", 'utf8');
|
|
13
12
|
|
|
14
13
|
const SOUNDCLOUD_REGEX = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g;
|
|
15
14
|
|
|
@@ -48,7 +47,7 @@ const fastFetch = (url, options = {}) => {
|
|
|
48
47
|
const soundAutoPlay = async (baseUrl) => {
|
|
49
48
|
try {
|
|
50
49
|
const html = await fastFetch(`${baseUrl}/recommended`);
|
|
51
|
-
|
|
50
|
+
|
|
52
51
|
const links = [];
|
|
53
52
|
let match;
|
|
54
53
|
while ((match = SOUNDCLOUD_REGEX.exec(html)) && links.length < 50) {
|
|
@@ -64,51 +63,47 @@ const soundAutoPlay = async (baseUrl) => {
|
|
|
64
63
|
}
|
|
65
64
|
};
|
|
66
65
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
const spotifyAutoPlay = async (seed, player, requester, excludedIdentifiers = []) => {
|
|
67
|
+
try {
|
|
68
|
+
const { trackId, artistIds } = seed
|
|
69
|
+
if (!trackId) return null
|
|
70
|
+
|
|
71
|
+
const prevIdentifier = player.current?.identifier
|
|
72
|
+
let seedQuery = `seed_tracks=${trackId}`
|
|
73
|
+
if (artistIds) seedQuery += `&seed_artists=${artistIds}`
|
|
74
|
+
console.log('Seed query:', seedQuery)
|
|
75
|
+
|
|
76
|
+
const response = await player.aqua.resolve({
|
|
77
|
+
query: seedQuery,
|
|
78
|
+
source: 'spsearch',
|
|
79
|
+
requester
|
|
80
|
+
})
|
|
81
|
+
const candidates = response?.tracks || []
|
|
82
|
+
|
|
83
|
+
const seenIds = new Set(excludedIdentifiers)
|
|
84
|
+
if (prevIdentifier) seenIds.add(prevIdentifier)
|
|
85
|
+
|
|
86
|
+
const result = []
|
|
87
|
+
for (const track of candidates) {
|
|
88
|
+
const { identifier } = track
|
|
89
|
+
if (seenIds.has(identifier)) continue
|
|
90
|
+
seenIds.add(identifier)
|
|
91
|
+
track.pluginInfo = {
|
|
92
|
+
...(track.pluginInfo || {}),
|
|
93
|
+
clientData: { fromAutoplay: true }
|
|
94
|
+
}
|
|
95
|
+
result.push(track)
|
|
96
|
+
if (result.length === 5) break
|
|
97
|
+
}
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
const [totp, ts] = generateToken();
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
const tokenUrl = `https://open.spotify.com/api/token?reason=init&productType=embed&totp=${totp}&totpVer=5&ts=${ts}`;
|
|
93
|
-
const tokenResponse = await fastFetch(tokenUrl);
|
|
94
|
-
const { accessToken } = JSON.parse(tokenResponse);
|
|
95
|
-
|
|
96
|
-
if (!accessToken) throw new Error("No access token");
|
|
97
|
-
|
|
98
|
-
const recUrl = `https://api.spotify.com/v1/recommendations?limit=10&seed_tracks=${seedTrackId}`;
|
|
99
|
-
const recResponse = await fastFetch(recUrl, {
|
|
100
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
101
|
-
});
|
|
99
|
+
return result
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error('Spotify autoplay error:', err)
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
105
|
+
}
|
|
105
106
|
|
|
106
|
-
return tracks[Math.random() * tracks.length | 0].id;
|
|
107
|
-
} catch (err) {
|
|
108
|
-
console.error("Spotify error:", err.message);
|
|
109
|
-
throw err;
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
107
|
|
|
113
108
|
module.exports = {
|
|
114
109
|
scAutoPlay: soundAutoPlay,
|