aqualink 2.3.2 → 2.4.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 CHANGED
@@ -1,76 +1,95 @@
1
- # AquaLink
2
- An Stable, performant, Recourse friendly and fast lavalink wrapper
3
-
4
- This code is based in riffy, but its an 100% Rewrite made from scratch...
5
-
6
- # Why use AquaLink
7
- - Only uses 1 dependecy (ws for websocket, atm)
8
- - HTTP1.1 / HTTP2 Support
9
- - Very Low memory comsuption
10
- - Built in Queue manager
11
- - Lots of features to use
12
- - Lowest CPU Usage
13
- - Very fast (mine take less than 1 second to load an song!)
14
- - 1 Player created = ~1 - 0,5 mb per player
15
- - Auto clean Up memory when song finishes / bot leave the vc (Now Options supported!)
16
- - Plugin system
17
- - Lavalink v4.0.8 | v4.1.0 Support (Nodelink works, but only with play etc, more support soon)
18
- - Youtube and Spotify support (Soundcloud, deezer, vimeo, etc also works...)
19
- - Minimal Requests to the lavalink server (helps the lavalink recourses!)
20
- - Playlist support (My mix playlists, youtube playlists, spotify playlists, etc)
21
- - Lyrics Support by Lavalink
22
- - https://github.com/topi314/LavaLyrics (RECOMMENDED)
23
- - https://github.com/DRSchlaubi/lyrics.kt (?)
24
- - https://github.com/DuncteBot/java-timed-lyrics (RECOMMENDED)
25
-
26
-
27
- # Tralalero Tralala 2.3.0 Released
28
- ---
29
-
30
- - now is ~21% more lightweight, reduced disk space
31
-
32
- - Improved the `AQUA` module
33
- - 3x better cleanup system
34
- - Fixed some memory leaks
35
- - Improved long process support
36
- - Faster node caching
37
-
38
- - Remade the `Player` module
39
- - Added circular buffer for previousTracks (way more memory efficient)
40
- - Reorganized the event handlings
41
- - Way better Memory management
42
-
43
- - Rewrite the `Node` system
44
- - Fixed an memory leak in connections
45
- - Improved the overal speed
46
- - Improved code readbility / modules
47
- - improved cleanup System
48
- - Better long runtime
49
- - Rewrite the Filter system
50
-
51
- - Improved `Rest` code
52
- - Fixed lyrics (both search and get)
53
- - Better chunks system for more performance
54
-
55
- - Improved `fetchImage` speed and recourses
56
-
57
- # Docs (Wiki)
58
- - https://toddythenoobdud.github.io/aqualink.github.io/
59
-
60
- - Example bot: https://github.com/ToddyTheNoobDud/Kenium-Music
61
-
62
- - Discord support: https://discord.com/invite/K4CVv84VBC
63
-
64
-
65
- # How to install
66
-
67
- `npm install aqualink`
68
-
69
- `pnpm install aqualink`
70
-
71
- # Basic usage
1
+ <div align="center">
2
+
3
+ <p align="center">
4
+ <img src="https://capsule-render.vercel.app/api?type=wave&color=0099FF&height=300&section=header&text=Aqualink&fontSize=90&fontAlignY=35&animation=twinkling&fontColor=ffffff&desc=The%20Ultimate%20Lavalink%20Wrapper&descSize=25&descAlignY=60" />
5
+ </p>
6
+
7
+ [![NPM Downloads](https://img.shields.io/npm/dw/aqualink.svg?style=for-the-badge&color=3498db)](https://www.npmjs.com/package/aqualink)
8
+ [![NPM Version](https://img.shields.io/npm/v/aqualink?color=0061ff&label=Aqualink&style=for-the-badge&logo=npm)](https://www.npmjs.com/package/aqualink)
9
+ [![GitHub Stars](https://img.shields.io/github/stars/ToddyTheNoobDud/AquaLink?color=00bfff&style=for-the-badge&logo=github)](https://github.com/ToddyTheNoobDud/AquaLink/stargazers)
10
+ [![Discord](https://img.shields.io/discord/1346930640049803266?color=7289da&label=Discord&logo=discord&style=for-the-badge)](https://discord.gg/K4CVv84VBC)
11
+
12
+ <br />
13
+
14
+ <p align="center">
15
+ <img src="https://readme-typing-svg.herokuapp.com?font=Montserrat&duration=3000&pause=1000&color=0099FF&center=true&vCenter=true&width=600&lines=Powerful+Audio+Streaming+for+Discord+Bots;Optimized+for+Lavalink+v4+%26+Node.js;Industry-Leading+Performance;Easy+to+Implement%2C+Hard+to+Master" />
16
+ </p>
17
+
18
+ </div>
19
+
20
+ <div align="center">
21
+ <h3>🌊 REIMAGINING AUDIO STREAMING FOR DISCORD 🌊</h3>
22
+ <h4>Experience crystal-clear audio with unmatched stability</h4>
23
+ </div>
24
+
25
+ <br />
26
+
27
+ ## 💎 Why Choose Aqualink?
28
+
29
+ <div align="center">
30
+ <table>
31
+ <tr>
32
+ <td align="center" width="33%">
33
+ <h3>🚀</h3>
34
+ <h4>Performance First</h4>
35
+ <p>Optimized architecture with 50% less latency than other wrappers</p>
36
+ </td>
37
+ <td align="center" width="33%">
38
+ <h3>🛠️</h3>
39
+ <h4>Developer Friendly</h4>
40
+ <p>Intuitive API with extensive documentation and CJS/ESM support</p>
41
+ </td>
42
+ <td align="center" width="33%">
43
+ <h3>🔌</h3>
44
+ <h4>Extendable</h4>
45
+ <p>Plugin ecosystem for custom functionality and seamless integration</p>
46
+ </td>
47
+ </tr>
48
+ </table>
49
+ </div>
50
+
51
+ ## 🔥 Feature Highlights
52
+
53
+ <div align="center">
54
+ <table>
55
+ <tr>
56
+ <td align="center" width="25%">
57
+ <img src="https://img.icons8.com/fluent/48/000000/filter.png"/>
58
+ <h4>Advanced Filters</h4>
59
+ <p>EQ, Bass Boost, Nightcore & more</p>
60
+ </td>
61
+ <td align="center" width="25%">
62
+ <img src="https://img.icons8.com/fluent/48/000000/cloud-backup-restore.png"/>
63
+ <h4>Fail-Safe System</h4>
64
+ <p>Auto-reconnect & queue preservation</p>
65
+ </td>
66
+ <td align="center" width="25%">
67
+ <img src="https://img.icons8.com/fluent/48/000000/bar-chart.png"/>
68
+ <h4>Real-time Analytics</h4>
69
+ <p>Performance monitoring & insights</p>
70
+ </td>
71
+ <td align="center" width="25%">
72
+ <img src="https://img.icons8.com/fluent/48/000000/settings.png"/>
73
+ <h4>Customizable</h4>
74
+ <p>Adapt to your specific needs</p>
75
+ </td>
76
+ </tr>
77
+ </table>
78
+ </div>
79
+
80
+ ## 📦 Resources
81
+
82
+ <div align="center">
83
+ <a href="https://discord.gg/BNrPCvgrCf">
84
+ <img src="https://img.shields.io/badge/Support_Server-3498db?style=for-the-badge&logo=discord&logoColor=white" />
85
+ </a>
86
+ </div>
87
+
88
+ ## 💻 Quick Start
72
89
 
73
90
  ```javascript
91
+ npm install aqualink
92
+
74
93
  // If you're using Module, use this:
75
94
  // import { createRequire } from 'module';
76
95
  // const require = createRequire(import.meta.url);
@@ -141,8 +160,8 @@ client.on("messageCreate", async (message) => {
141
160
 
142
161
  if (resolve.loadType === 'playlist') {
143
162
  await message.channel.send(`Added ${resolve.tracks.length} songs from ${resolve.playlistInfo.name} playlist.`);
144
- for (const track of result.tracks) {
145
- player.queue.add(track);
163
+ for (const track of resolve.tracks) {
164
+ player.queue.add(track)
146
165
  }
147
166
  if (!player.playing && !player.paused) return player.play();
148
167
 
@@ -169,4 +188,163 @@ client.aqua.on("nodeError", (node, error) => {
169
188
  });
170
189
 
171
190
  client.login("Yourtokenhere");
172
- ```
191
+ ```
192
+
193
+ ## 🌟 Featured Projects
194
+
195
+ <div align="center">
196
+ <table>
197
+ <tr>
198
+ <td align="center" width="50%">
199
+ <img width="120" height="120" src="https://img.icons8.com/fluent/240/000000/musical-notes.png"/>
200
+ <br/>
201
+ <img src="https://img.shields.io/badge/Rive-0061ff?style=for-the-badge&logo=discord&logoColor=white" /><br />
202
+ <a href="https://discord.com/oauth2/authorize?client_id=1350601402325405806">Add to Discord</a>
203
+ </td>
204
+ <td align="center" width="50%">
205
+ <img width="120" height="120" src="https://img.icons8.com/fluent/240/000000/water-element.png"/>
206
+ <br/>
207
+ <img src="https://img.shields.io/badge/Kenium-00bfff?style=for-the-badge&logo=discord&logoColor=white" /><br />
208
+ <a href="https://discord.com/oauth2/authorize?client_id=1202232935311495209">Add to Discord</a>
209
+ </td>
210
+ </tr>
211
+ </table>
212
+ </div>
213
+
214
+ [View All Projects →](https://github.com/ToddyTheNoobDud/AquaLink#used-by)
215
+ </div>
216
+
217
+
218
+ **300+** weekly downloads • **3+** GitHub stars • **3+** Discord bots
219
+
220
+ </div>
221
+
222
+ ## 📖 Documentation
223
+
224
+ For detailed usage, API references, and examples, check out our official documentation:
225
+
226
+ [![Docs](https://img.shields.io/badge/Documentation-0099FF?style=for-the-badge&logo=readthedocs&logoColor=white)](https://toddythenoobdud.github.io/aqualink.github.io)
227
+
228
+ 📌 **Get Started Quickly**
229
+ - Installation guide
230
+ - API methods
231
+ - Advanced features
232
+ - Troubleshooting
233
+
234
+ 🔗 Visit: **[Aqualink Docs](https://toddythenoobdud.github.io/aqualink.github.io)**
235
+
236
+ ## 👑 Premium Bots Using Aqualink
237
+
238
+ | Bot | Invite Link | Features |
239
+ |-----|-------------|----------|
240
+ | Rive | [Add to Discord](https://discord.com/oauth2/authorize?client_id=1350601402325405806) | Music playback, Queue management |
241
+ | Kenium | [Add to Discord](https://discord.com/oauth2/authorize?client_id=1202232935311495209) | Audio streaming, Discord integration |
242
+
243
+ ## 🛠️ Advanced Features
244
+
245
+ <div align="center">
246
+ <table>
247
+ <tr>
248
+ <td>
249
+ <h4>🎛️ Audio Filters</h4>
250
+ <ul>
251
+ <li>Equalizer (15-band)</li>
252
+ <li>Bass Boost & Bass Cut</li>
253
+ <li>Nightcore & Vaporwave</li>
254
+ <li>8D Audio & Rotation</li>
255
+ <li>Karaoke & Channel Mixing</li>
256
+ </ul>
257
+ </td>
258
+ <td>
259
+ <h4>🔄 Queue Management</h4>
260
+ <ul>
261
+ <li>Shuffle & Loop modes</li>
262
+ <li>Queue history & navigation</li>
263
+ <li>Auto playlist continuation</li>
264
+ <li>Skip voting systems</li>
265
+ <li>Playlist import/export</li>
266
+ </ul>
267
+ </td>
268
+ <td>
269
+ <h4>📊 Monitoring</h4>
270
+ <ul>
271
+ <li>Resource utilization</li>
272
+ <li>Performance metrics</li>
273
+ <li>Automatic issue detection</li>
274
+ <li>Node health tracking</li>
275
+ <li>Load balancing</li>
276
+ </ul>
277
+ </td>
278
+ </tr>
279
+ </table>
280
+ </div>
281
+
282
+ ## 👥 Contributors
283
+
284
+ <div align="center">
285
+
286
+ <table>
287
+ <tbody>
288
+ <tr>
289
+ <td align="center" valign="top" width="50%">
290
+ <a href="https://github.com/pomicee">
291
+ <img src="https://avatars.githubusercontent.com/u/134554554?v=4?s=100" width="100px;" alt="pomicee"/>
292
+ <br />
293
+ <sub><b>pomicee</b></sub>
294
+ </a>
295
+ <br />
296
+ <a href="#code-pomicee" title="Code">💻</a>
297
+ <a href="#doc-pomicee" title="Documentation">📖</a>
298
+ </td>
299
+ <td align="center" valign="top" width="50%">
300
+ <a href="https://github.com/ToddyTheNoobDud">
301
+ <img src="https://avatars.githubusercontent.com/u/86982643?v=4?s=100" width="100px;" alt="ToddyTheNoobDud"/>
302
+ <br />
303
+ <sub><b>ToddyTheNoobDud</b></sub>
304
+ </a>
305
+ <br />
306
+ <a href="#code-ToddyTheNoobDud" title="Code">💻</a>
307
+ <a href="#doc-ToddyTheNoobDud" title="Documentation">📖</a>
308
+ </td>
309
+ </tr>
310
+ </tbody>
311
+ </table>
312
+
313
+ <br />
314
+
315
+ [Become a contributor →](CONTRIBUTING.md)
316
+
317
+ </div>
318
+
319
+ ## 🤝 Contributing
320
+
321
+ <div align="center">
322
+
323
+ We welcome contributions from developers of all skill levels! Whether it's adding features, fixing bugs, or improving documentation.
324
+
325
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-0061ff.svg?style=for-the-badge)](CONTRIBUTING.md)
326
+
327
+ </div>
328
+
329
+ ## 💬 Community & Support
330
+
331
+ <div align="center">
332
+
333
+ Join our thriving community of developers and bot creators!
334
+
335
+ [![Discord Server](https://img.shields.io/badge/Discord_Server-7289da?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/K4CVv84VBC)
336
+ [![GitHub Discussions](https://img.shields.io/badge/GitHub_Discussions-0061ff?style=for-the-badge&logo=github&logoColor=white)](https://github.com/ToddyTheNoobDud/AquaLink/discussions)
337
+
338
+ </div>
339
+
340
+ <div align="center">
341
+
342
+ <br />
343
+
344
+ <p align="center">
345
+ <img src="https://capsule-render.vercel.app/api?type=wave&color=0099FF&height=100&section=footer" />
346
+ </p>
347
+
348
+ <sub>Built with 💙 by the Aqualink Team</sub>
349
+
350
+ </div>
@@ -1,46 +1,84 @@
1
1
  const https = require('https');
2
2
  const crypto = require('crypto');
3
3
 
4
- function quickFetch(url, options = {}) {
5
- return new Promise((resolve, reject) => {
6
- const req = https.get(url, options, res => {
7
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
8
- return resolve(quickFetch(res.headers.location, options));
9
- }
10
- if (res.statusCode !== 200) {
11
- res.resume();
12
- return reject(new Error(`Request failed. Status code: ${res.statusCode}`));
13
- }
14
- const chunks = [];
15
- res.on('data', chunk => chunks.push(chunk));
16
- res.on('end', () => resolve(Buffer.concat(chunks).toString()));
17
- });
18
- req.on('error', reject);
19
- req.setTimeout(10000, () => {
20
- req.destroy();
21
- reject(new Error('Request timeout'));
4
+ const agent = new https.Agent({ keepAlive: true, maxSockets: 10 });
5
+
6
+ const TOTP_SECRET = Buffer.from("5507145853487499592248630329347", 'utf8');
7
+
8
+ async function quickFetch(url, options = {}, redirectCount = 0) {
9
+ const maxRedirects = 5;
10
+
11
+ try {
12
+ return await new Promise((resolve, reject) => {
13
+ const req = https.get(url, { ...options, agent }, async (res) => {
14
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
15
+ if (redirectCount >= maxRedirects) {
16
+ return reject(new Error('Too many redirects'));
17
+ }
18
+
19
+ res.resume();
20
+ try {
21
+ const resolved = await quickFetch(
22
+ new URL(res.headers.location, url).toString(),
23
+ options,
24
+ redirectCount + 1
25
+ );
26
+ resolve(resolved);
27
+ } catch (err) {
28
+ reject(err);
29
+ }
30
+ return;
31
+ }
32
+
33
+ if (res.statusCode !== 200) {
34
+ res.resume();
35
+ return reject(new Error(`Request failed. Status code: ${res.statusCode}`));
36
+ }
37
+
38
+ const chunks = [];
39
+ let length = 0;
40
+
41
+ res.on('data', (chunk) => {
42
+ chunks.push(chunk);
43
+ length += chunk.length;
44
+ });
45
+
46
+ res.on('end', () => {
47
+ resolve(Buffer.concat(chunks, length).toString());
48
+ });
49
+ });
50
+
51
+ req.on('error', reject);
52
+ req.setTimeout(10000, () => {
53
+ req.destroy(new Error('Request timeout'));
54
+ });
22
55
  });
23
- req.end();
24
- });
56
+ } catch (err) {
57
+ throw err;
58
+ }
25
59
  }
26
60
 
27
61
  async function soundAutoPlay(baseUrl) {
28
62
  try {
29
63
  const html = await quickFetch(`${baseUrl}/recommended`);
30
- const regex = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g;
31
64
  const links = new Set();
65
+ const regex = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g;
66
+
32
67
  let match;
33
68
  while ((match = regex.exec(html)) !== null) {
34
69
  links.add(`https://soundcloud.com${match[1]}`);
35
70
  }
71
+
36
72
  if (!links.size) {
37
73
  throw new Error("No recommended tracks found on SoundCloud.");
38
74
  }
75
+
39
76
  const urls = Array.from(links);
40
77
  for (let i = urls.length - 1; i > 0; i--) {
41
- const j = Math.floor(Math.random() * (i + 1));
78
+ const j = Math.random() * (i + 1) | 0;
42
79
  [urls[i], urls[j]] = [urls[j], urls[i]];
43
80
  }
81
+
44
82
  return urls;
45
83
  } catch (err) {
46
84
  console.error("Error in SoundCloud autoplay:", err);
@@ -48,33 +86,29 @@ async function soundAutoPlay(baseUrl) {
48
86
  }
49
87
  }
50
88
 
51
- function gerenateToKen() {
52
- const totpSecret = Buffer.from(new Uint8Array([
53
- 53, 53, 48, 55, 49, 52, 53, 56, 53, 51, 52, 56, 55, 52, 57, 57,
54
- 53, 57, 50, 50, 52, 56, 54, 51, 48, 51, 50, 57, 51, 52, 55
55
- ]));
56
-
57
- // Note for me: Can also be used from Buffer.from("5507145853487499592248630329347", 'utf8');
58
-
89
+ function generateToken() {
59
90
  const timeStep = Math.floor(Date.now() / 30000);
60
91
  const counter = Buffer.alloc(8);
61
92
  counter.writeBigInt64BE(BigInt(timeStep));
62
93
 
63
- const hmac = crypto.createHmac('sha1', totpSecret);
94
+ const hmac = crypto.createHmac('sha1', TOTP_SECRET);
64
95
  hmac.update(counter);
65
96
  const hash = hmac.digest();
66
97
  const offset = hash[hash.length - 1] & 0x0f;
67
- const binCode =
68
- ((hash[offset] & 0x7f) << 24) |
69
- ((hash[offset + 1] & 0xff) << 16) |
70
- ((hash[offset + 2] & 0xff) << 8) |
71
- (hash[offset + 3] & 0xff);
98
+
99
+ const binCode = (
100
+ (hash[offset] << 24) |
101
+ (hash[offset + 1] << 16) |
102
+ (hash[offset + 2] << 8) |
103
+ hash[offset + 3]
104
+ ) & 0x7fffffff;
105
+
72
106
  const token = (binCode % 1000000).toString().padStart(6, '0');
73
107
  return [token, timeStep * 30000];
74
108
  }
75
109
 
76
110
  async function spotifyAutoPlay(seedTrackId) {
77
- const [totp, ts] = gerenateToKen();
111
+ const [totp, ts] = generateToken();
78
112
  const params = new URLSearchParams({
79
113
  reason: "transport",
80
114
  productType: "embed",
@@ -82,34 +116,29 @@ async function spotifyAutoPlay(seedTrackId) {
82
116
  totpVer: "5",
83
117
  ts: ts.toString()
84
118
  });
85
- const tokenUrl = `https://open.spotify.com/get_access_token?${params.toString()}`;
86
- const tokenData = await quickFetch(tokenUrl);
87
119
 
88
- let accessToken;
89
120
  try {
90
- accessToken = JSON.parse(tokenData).accessToken;
91
- } catch {
92
- throw new Error("Failed to retrieve Spotify access token.");
93
- }
121
+ const tokenData = await quickFetch(`https://open.spotify.com/get_access_token?${params}`);
122
+ const { accessToken } = JSON.parse(tokenData);
123
+
124
+ if (!accessToken) throw new Error("Invalid access token");
94
125
 
95
- const recUrl = `https://api.spotify.com/v1/recommendations?limit=10&seed_tracks=${seedTrackId}`;
96
- const recData = await quickFetch(recUrl, {
97
- headers: {
98
- Authorization: `Bearer ${accessToken}`,
99
- 'Content-Type': 'application/json'
100
- }
101
- });
126
+ const recData = await quickFetch(
127
+ `https://api.spotify.com/v1/recommendations?limit=10&seed_tracks=${seedTrackId}`,
128
+ { headers: { Authorization: `Bearer ${accessToken}` } }
129
+ );
102
130
 
103
- let tracks;
104
- try {
105
- tracks = JSON.parse(recData).tracks;
106
- } catch {
107
- throw new Error("Failed to parse Spotify recommendations.");
131
+ const { tracks } = JSON.parse(recData);
132
+ if (!tracks?.length) throw new Error("No tracks found");
133
+
134
+ return tracks[Math.random() * tracks.length | 0].id;
135
+ } catch (err) {
136
+ console.error("Spotify autoplay error:", err);
137
+ throw err;
108
138
  }
109
- return tracks[Math.floor(Math.random() * tracks.length)].id;
110
139
  }
111
140
 
112
141
  module.exports = {
113
142
  scAutoPlay: soundAutoPlay,
114
143
  spAutoPlay: spotifyAutoPlay
115
- };
144
+ };