aqualink 2.1.3 → 2.3.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
@@ -22,50 +22,44 @@ This code is based in riffy, but its an 100% Rewrite made from scratch...
22
22
  - https://github.com/topi314/LavaLyrics (RECOMMENDED)
23
23
  - https://github.com/DRSchlaubi/lyrics.kt (?)
24
24
  - https://github.com/DuncteBot/java-timed-lyrics (RECOMMENDED)
25
-
26
- # Tralalero Tralala 2.1.0 Released
25
+
26
+
27
+ # Tralalero Tralala 2.3.0 Released
27
28
  ---
29
+
30
+ - now is ~21% more lightweight, reduced disk space
31
+
28
32
  - Improved the `AQUA` module
29
- - Faster nodes loading
30
- - Faster plugin loading
31
- - Better listeners for player
32
- - Faster resolving system for playlists
33
-
34
- - Remade the `Connection` system
35
- - Less overheard now.
36
- - Faster connections
37
- - Improved the checkings
38
- - Improved error handling
39
- - Fixed creating useless Objects and arrays
40
-
41
- - Fully rewrite the `Node` system
42
- - Way faster connections
43
- - More stable (i think so)
44
- - Faster events / messages / payloads handling
45
- - Better stats handling (reusing, creating, destroyin)
46
- - Some more bug fixes and stuff i forgot.
33
+ - 3x better cleanup system
34
+ - Fixed some memory leaks
35
+ - Improved long process support
36
+ - Faster node caching
47
37
 
48
38
  - Remade the `Player` module
49
- - Now support Lazy Loading by default
50
- - Better State Updates
51
- - Improved Garbage Collection
52
- - Rewrite to use direct comparasions
39
+ - Added circular buffer for previousTracks (way more memory efficient)
40
+ - Reorganized the event handlings
41
+ - Way better Memory management
53
42
 
54
- - Improved the `Rest` module
55
- - Lazy loading of http2
56
- - Faster request chunks
57
- - Some overall upgrades
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
58
50
 
59
- - Improved `Track` module
60
- - Faster track looking
61
- - More micro optimizations (use Boolean instead of !!)
51
+ - Improved `Rest` code
52
+ - Fixed lyrics (both search and get)
53
+ - Better chunks system for more performance
62
54
 
63
- - Remade the INDEX.D.TS File: Added more 1000 lines of code. Added autocomplete, options, and documented everything.
55
+ - Improved `fetchImage` speed and recourses
64
56
 
65
57
  # Docs (Wiki)
66
- - https://github.com/ToddyTheNoobDud/AquaLink/wiki
58
+ - https://toddythenoobdud.github.io/aqualink.github.io/
59
+
60
+ - Example bot: https://github.com/ToddyTheNoobDud/Kenium-Music
67
61
 
68
- - Example bot: https://github.com/ToddyTheNoobDud/Thorium-Music
62
+ - Discord support: https://discord.com/invite/K4CVv84VBC
69
63
 
70
64
 
71
65
  # How to install
@@ -147,7 +141,9 @@ client.on("messageCreate", async (message) => {
147
141
 
148
142
  if (resolve.loadType === 'playlist') {
149
143
  await message.channel.send(`Added ${resolve.tracks.length} songs from ${resolve.playlistInfo.name} playlist.`);
150
- player.queue.add(resolve.tracks);
144
+ for (const track of result.tracks) {
145
+ player.queue.add(track);
146
+ }
151
147
  if (!player.playing && !player.paused) return player.play();
152
148
 
153
149
  } else if (resolve.loadType === 'search' || resolve.loadType === 'track') {
@@ -3,15 +3,30 @@ const https = require('https');
3
3
  function fetch(url, options = {}) {
4
4
  return new Promise((resolve, reject) => {
5
5
  const req = https.get(url, options, (res) => {
6
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
7
+ return fetch(res.headers.location, options).then(resolve).catch(reject);
8
+ }
9
+
6
10
  if (res.statusCode !== 200) {
11
+ res.resume();
7
12
  reject(new Error(`Request failed. Status code: ${res.statusCode}`));
8
13
  return;
9
14
  }
10
- let data = '';
11
- res.on('data', (chunk) => data += chunk);
12
- res.on('end', () => resolve(data));
15
+
16
+ const chunks = [];
17
+ res.on('data', chunk => chunks.push(chunk));
18
+ res.on('end', () => resolve(Buffer.concat(chunks).toString()));
19
+ });
20
+
21
+ req.setTimeout(10000, () => {
22
+ req.destroy();
23
+ reject(new Error('Request timeout'));
24
+ });
25
+
26
+ req.on('error', err => {
27
+ reject(err);
13
28
  });
14
- req.on('error', reject);
29
+
15
30
  req.end();
16
31
  });
17
32
  }
@@ -20,15 +35,23 @@ async function scAutoPlay(url) {
20
35
  try {
21
36
  const html = await fetch(`${url}/recommended`);
22
37
 
23
- const matches = [...html.matchAll(/<a itemprop="url" href="(\/.*?)"/g)];
38
+ const regex = /<a itemprop="url" href="(\/.*?)"/g;
39
+ const hrefs = new Set();
40
+ let match;
24
41
 
25
- const hrefs = [...new Set(matches.map(match => `https://soundcloud.com${match[1]}`))];
42
+ while ((match = regex.exec(html)) !== null) {
43
+ hrefs.add(`https://soundcloud.com${match[1]}`);
44
+ }
26
45
 
27
- if (hrefs.length === 0) {
46
+ if (hrefs.size === 0) {
28
47
  throw new Error("No recommended tracks found on SoundCloud.");
29
48
  }
30
49
 
31
- const shuffledHrefs = hrefs.sort(() => Math.random() - 0.5);
50
+ const shuffledHrefs = Array.from(hrefs);
51
+ for (let i = shuffledHrefs.length - 1; i > 0; i--) {
52
+ const j = Math.floor(Math.random() * (i + 1));
53
+ [shuffledHrefs[i], shuffledHrefs[j]] = [shuffledHrefs[j], shuffledHrefs[i]];
54
+ }
32
55
 
33
56
  return shuffledHrefs;
34
57
  } catch (error) {
@@ -40,21 +63,28 @@ async function scAutoPlay(url) {
40
63
  async function spAutoPlay(track_id) {
41
64
  try {
42
65
  const tokenResponse = await fetch("https://open.spotify.com/get_access_token?reason=transport&productType=embed");
43
- const { accessToken } = JSON.parse(tokenResponse);
66
+ const tokenData = JSON.parse(tokenResponse);
67
+ const accessToken = tokenData?.accessToken;
44
68
 
45
69
  if (!accessToken) throw new Error("Failed to retrieve Spotify access token");
46
70
 
47
- const recommendationsResponse = await fetch(`https://api.spotify.com/v1/recommendations?limit=10&seed_tracks=${track_id}`, {
48
- headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' }
49
- });
71
+ const recommendationsResponse = await fetch(
72
+ `https://api.spotify.com/v1/recommendations?limit=5&seed_tracks=${track_id}&fields=tracks.id`,
73
+ {
74
+ headers: {
75
+ Authorization: `Bearer ${accessToken}`,
76
+ 'Content-Type': 'application/json'
77
+ }
78
+ }
79
+ );
50
80
 
51
- const { tracks } = JSON.parse(recommendationsResponse);
81
+ const data = JSON.parse(recommendationsResponse);
82
+ const tracks = data?.tracks || [];
52
83
 
53
- if (!tracks || tracks.length === 0) {
84
+ if (tracks.length === 0) {
54
85
  throw new Error("No recommended tracks found on Spotify.");
55
86
  }
56
87
 
57
- // Return a random track ID
58
88
  return tracks[Math.floor(Math.random() * tracks.length)].id;
59
89
  } catch (error) {
60
90
  console.error("Error fetching Spotify recommendations:", error);
@@ -1,10 +1,11 @@
1
- const http2 = require('http2');
1
+ const https = require('https');
2
2
  const sourceHandlers = new Map([
3
3
  ['spotify', uri => fetchThumbnail(`https://open.spotify.com/oembed?url=${uri}`)],
4
4
  ['youtube', identifier => fetchYouTubeThumbnail(identifier)]
5
5
  ]);
6
6
  const YOUTUBE_URL_TEMPLATE = (quality) => (id) => `https://img.youtube.com/vi/${id}/${quality}.jpg`;
7
7
  const YOUTUBE_QUALITIES = ['maxresdefault', 'hqdefault', 'mqdefault', 'default'].map(YOUTUBE_URL_TEMPLATE);
8
+
8
9
  async function getImageUrl(info) {
9
10
  if (!info?.sourceName || !info?.uri) return null;
10
11
  const handler = sourceHandlers.get(info.sourceName.toLowerCase());
@@ -16,42 +17,34 @@ async function getImageUrl(info) {
16
17
  return null;
17
18
  }
18
19
  }
20
+
19
21
  function fetchThumbnail(url) {
20
22
  return new Promise((resolve, reject) => {
21
- const client = http2.connect(url);
22
-
23
- const req = client.request({ ':path': '/' });
24
-
25
- let data = '';
26
-
27
- req.on('response', (headers, flags) => {
28
- if (headers[':status'] !== 200) {
29
- return reject(`Failed to fetch: ${headers[':status']}`);
23
+ https.get(url, (res) => {
24
+ if (res.statusCode !== 200) {
25
+ res.resume();
26
+ return reject(`Failed to fetch: ${res.statusCode}`);
30
27
  }
31
- });
32
- req.on('data', chunk => {
33
- data += chunk;
34
- });
35
- req.on('end', () => {
36
- try {
37
- const json = JSON.parse(data);
38
- resolve(json.thumbnail_url || null);
39
- } catch (error) {
40
- reject(`JSON parse error: ${error.message}`);
41
- } finally {
42
- client.close();
43
- }
44
- });
45
- req.on('error', (error) => {
28
+ let data = '';
29
+ res.on('data', chunk => data += chunk);
30
+ res.on('end', () => {
31
+ try {
32
+ const json = JSON.parse(data);
33
+ resolve(json.thumbnail_url || null);
34
+ } catch (error) {
35
+ reject(`JSON parse error: ${error.message}`);
36
+ }
37
+ });
38
+ }).on('error', (error) => {
46
39
  reject(`Request error: ${error.message}`);
47
- client.close();
48
40
  });
49
- req.end();
50
41
  });
51
42
  }
43
+
52
44
  async function fetchYouTubeThumbnail(identifier) {
53
45
  const promises = YOUTUBE_QUALITIES.map(urlFunc => fetchThumbnail(urlFunc(identifier)));
54
- const results = await Promise.race(promises);
55
- return results || null;
46
+ const firstResult = await Promise.race(promises);
47
+ return firstResult || null;
56
48
  }
57
- module.exports = { getImageUrl };
49
+
50
+ module.exports = { getImageUrl };