aqualink 2.6.1-fix → 2.6.1-fix3

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.
@@ -1,142 +1,114 @@
1
1
  const https = require('https');
2
2
  const crypto = require('crypto');
3
3
 
4
- const agent = new https.Agent({ keepAlive: true, maxSockets: 10 });
4
+ const agent = new https.Agent({
5
+ keepAlive: true,
6
+ maxSockets: 5,
7
+ maxFreeSockets: 2,
8
+ timeout: 8000,
9
+ freeSocketTimeout: 4000
10
+ });
5
11
 
6
12
  const TOTP_SECRET = Buffer.from("5507145853487499592248630329347", 'utf8');
7
13
 
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
- });
55
- });
56
- } catch (err) {
57
- throw err;
14
+ const SOUNDCLOUD_REGEX = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g;
15
+
16
+ const shuffleArray = (arr) => {
17
+ for (let i = arr.length - 1; i > 0; i--) {
18
+ const j = Math.random() * (i + 1) | 0;
19
+ [arr[i], arr[j]] = [arr[j], arr[i]];
58
20
  }
59
- }
21
+ return arr;
22
+ };
23
+
24
+ const fastFetch = (url, options = {}) => {
25
+ return new Promise((resolve, reject) => {
26
+ const req = https.get(url, { ...options, agent }, (res) => {
27
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
28
+ res.resume();
29
+ return fastFetch(new URL(res.headers.location, url).href, options)
30
+ .then(resolve, reject);
31
+ }
32
+
33
+ if (res.statusCode !== 200) {
34
+ res.resume();
35
+ return reject(new Error(`HTTP ${res.statusCode}`));
36
+ }
37
+
38
+ const chunks = [];
39
+ res.on('data', chunk => chunks.push(chunk));
40
+ res.on('end', () => resolve(Buffer.concat(chunks).toString()));
41
+ });
42
+
43
+ req.on('error', reject);
44
+ req.setTimeout(8000, () => req.destroy(new Error('Timeout')));
45
+ });
46
+ };
60
47
 
61
- async function soundAutoPlay(baseUrl) {
48
+ const soundAutoPlay = async (baseUrl) => {
62
49
  try {
63
- const html = await quickFetch(`${baseUrl}/recommended`);
64
- const links = new Set();
65
- const regex = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g;
50
+ const html = await fastFetch(`${baseUrl}/recommended`);
66
51
 
52
+ const links = [];
67
53
  let match;
68
- while ((match = regex.exec(html)) !== null) {
69
- links.add(`https://soundcloud.com${match[1]}`);
70
- }
71
-
72
- if (!links.size) {
73
- throw new Error("No recommended tracks found on SoundCloud.");
54
+ while ((match = SOUNDCLOUD_REGEX.exec(html)) && links.length < 50) {
55
+ links.push(`https://soundcloud.com${match[1]}`);
74
56
  }
75
57
 
76
- const urls = Array.from(links);
77
- for (let i = urls.length - 1; i > 0; i--) {
78
- const j = Math.random() * (i + 1) | 0;
79
- [urls[i], urls[j]] = [urls[j], urls[i]];
80
- }
58
+ if (!links.length) throw new Error("No tracks found");
81
59
 
82
- return urls;
60
+ return shuffleArray(links);
83
61
  } catch (err) {
84
- console.error("Error in SoundCloud autoplay:", err);
62
+ console.error("SoundCloud error:", err.message);
85
63
  return [];
86
64
  }
87
- }
65
+ };
88
66
 
89
- function generateToken() {
90
- const timeStep = Math.floor(Date.now() / 30000);
91
- const counter = Buffer.alloc(8);
92
- counter.writeBigInt64BE(BigInt(timeStep));
67
+ const generateToken = () => {
68
+ const timeStep = (Date.now() / 30000) | 0;
69
+ const counter = Buffer.allocUnsafe(8);
70
+ counter.writeBigUInt64BE(BigInt(timeStep), 0);
93
71
 
94
- const hmac = crypto.createHmac('sha1', TOTP_SECRET);
95
- hmac.update(counter);
96
- const hash = hmac.digest();
97
- const offset = hash[hash.length - 1] & 0x0f;
72
+ const hash = crypto.createHmac('sha1', TOTP_SECRET).update(counter).digest();
73
+ const offset = hash[19] & 0x0f;
98
74
 
99
75
  const binCode = (
100
- (hash[offset] << 24) |
101
- (hash[offset + 1] << 16) |
102
- (hash[offset + 2] << 8) |
76
+ (hash[offset] & 0x7f) << 24 |
77
+ hash[offset + 1] << 16 |
78
+ hash[offset + 2] << 8 |
103
79
  hash[offset + 3]
104
- ) & 0x7fffffff;
80
+ );
105
81
 
106
- const token = (binCode % 1000000).toString().padStart(6, '0');
107
- return [token, timeStep * 30000];
108
- }
82
+ return [
83
+ (binCode % 1000000).toString().padStart(6, '0'),
84
+ timeStep * 30000
85
+ ];
86
+ };
109
87
 
110
- async function spotifyAutoPlay(seedTrackId) {
88
+ const spotifyAutoPlay = async (seedTrackId) => {
111
89
  const [totp, ts] = generateToken();
112
- const params = new URLSearchParams({
113
- reason: "transport",
114
- productType: "embed",
115
- totp,
116
- totpVer: "5",
117
- ts: ts.toString()
118
- });
119
-
90
+
120
91
  try {
121
- const tokenData = await quickFetch(`https://open.spotify.com/get_access_token?${params}`);
122
- const { accessToken } = JSON.parse(tokenData);
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);
123
95
 
124
- if (!accessToken) throw new Error("Invalid access token");
96
+ if (!accessToken) throw new Error("No access token");
125
97
 
126
- const recData = await quickFetch(
127
- `https://api.spotify.com/v1/recommendations?limit=10&seed_tracks=${seedTrackId}`,
128
- { headers: { Authorization: `Bearer ${accessToken}` } }
129
- );
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
+ });
130
102
 
131
- const { tracks } = JSON.parse(recData);
132
- if (!tracks?.length) throw new Error("No tracks found");
103
+ const { tracks } = JSON.parse(recResponse);
104
+ if (!tracks?.length) throw new Error("No tracks");
133
105
 
134
106
  return tracks[Math.random() * tracks.length | 0].id;
135
107
  } catch (err) {
136
- console.error("Spotify autoplay error:", err);
108
+ console.error("Spotify error:", err.message);
137
109
  throw err;
138
110
  }
139
- }
111
+ };
140
112
 
141
113
  module.exports = {
142
114
  scAutoPlay: soundAutoPlay,
@@ -58,13 +58,12 @@ class Player extends EventEmitter {
58
58
  this._updateTimeout = null;
59
59
  this._dataStore = new Map();
60
60
 
61
- this.on("playerUpdate", (state) => {
62
- if (state) {
63
- this.position = state.position ?? this.position;
64
- this.timestamp = state.timestamp ?? this.timestamp;
65
- this.ping = state.ping ?? this.ping;
66
- this.aqua.emit("playerUpdate", this, { state });
67
- }
61
+ this.on("playerUpdate", (packet) => {
62
+ this.position = packet.state.position;
63
+ this.connected = packet.state.connected;
64
+ this.ping = packet.state.ping;
65
+
66
+ this.aqua.emit("playerUpdate", this, packet);
68
67
  });
69
68
 
70
69
  this.on("event", async (payload) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aqualink",
3
- "version": "2.6.1-fix",
3
+ "version": "2.6.1-fix3",
4
4
  "description": "An Lavalink client, focused in pure performance and features",
5
5
  "main": "build/index.js",
6
6
  "types": "index.d.ts",