aqualink 3.1.0 → 3.2.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.
@@ -9,49 +9,32 @@ const AGENT_CONFIG = {
9
9
  freeSocketTimeout: 4000
10
10
  }
11
11
 
12
- // Shared agent reference - can be set from Rest module
13
- let sharedAgent = null
14
- const getAgent = () => {
15
- if (!sharedAgent) {
16
- sharedAgent = new https.Agent(AGENT_CONFIG)
17
- }
18
- return sharedAgent
19
- }
20
-
21
- // Allow Rest module to inject its agent
22
- const setSharedAgent = (agent) => {
23
- if (!agent) {
24
- sharedAgent = null
25
- return
26
- }
27
- if (agent && typeof agent.addRequest === 'function') {
28
- sharedAgent = agent
29
- }
30
- }
12
+ const defaultAgent = new https.Agent(AGENT_CONFIG)
31
13
 
32
14
  const SC_LINK_RE = /<a\s+itemprop="url"\s+href="(\/[^"]+)"/g
33
15
  const MAX_REDIRECTS = 3
34
16
  const MAX_RESPONSE_BYTES = 5 * 1024 * 1024 // 5 MB
35
17
  const MAX_SC_LINKS = 50
36
- const MAX_SP_RESULTS = 5
18
+ const _MAX_SP_RESULTS = 5
37
19
  const DEFAULT_TIMEOUT_MS = 8000
38
20
 
39
- const fastFetch = (url, depth = 0) =>
21
+ const fastFetch = (url, agent, depth = 0) =>
40
22
  new Promise((resolve, reject) => {
41
23
  if (depth > MAX_REDIRECTS) return reject(new Error('Too many redirects'))
42
24
 
43
25
  const req = https.get(
44
26
  url,
45
- { agent: getAgent(), timeout: DEFAULT_TIMEOUT_MS },
27
+ { agent: agent || defaultAgent, timeout: DEFAULT_TIMEOUT_MS },
46
28
  (res) => {
47
29
  const { statusCode, headers } = res
48
30
 
49
31
  if (statusCode >= 300 && statusCode < 400 && headers.location) {
50
32
  res.resume()
51
- return fastFetch(new URL(headers.location, url).href, depth + 1).then(
52
- resolve,
53
- reject
54
- )
33
+ return fastFetch(
34
+ new URL(headers.location, url).href,
35
+ agent,
36
+ depth + 1
37
+ ).then(resolve, reject)
55
38
  }
56
39
 
57
40
  if (statusCode !== 200) {
@@ -96,61 +79,79 @@ const shuffleInPlace = (arr) => {
96
79
  return arr
97
80
  }
98
81
 
99
- const scAutoPlay = async (baseUrl) => {
100
- try {
101
- const html = await fastFetch(`${baseUrl}/recommended`)
102
- const links = []
103
- for (const m of html.matchAll(SC_LINK_RE)) {
104
- if (!m[1]) continue
105
- links.push(`https://soundcloud.com${m[1]}`)
106
- if (links.length >= MAX_SC_LINKS) break
107
- }
108
- return links.length ? shuffleInPlace(links) : []
109
- } catch (err) {
110
- console.error('scAutoPlay error:', err?.message || err)
111
- return []
82
+ const scAutoPlay = async (baseUrl, agent) => {
83
+ const html = await fastFetch(`${baseUrl}/recommended`, agent)
84
+ const links = []
85
+ for (const m of html.matchAll(SC_LINK_RE)) {
86
+ if (!m[1]) continue
87
+ links.push(`https://soundcloud.com${m[1]}`)
88
+ if (links.length >= MAX_SC_LINKS) break
112
89
  }
90
+ return links.length ? shuffleInPlace(links) : []
113
91
  }
114
92
 
115
93
  const spAutoPlay = async (seed, player, requester, excludedIds = []) => {
116
- try {
117
- if (!seed?.trackId) return null
94
+ if (!seed) return null
95
+
96
+ let trackId = seed.trackId !== 'local' ? seed.trackId : null
97
+ let isrc = seed.isrc || null
118
98
 
119
- const seedQuery = `seed_tracks=${seed.trackId}${seed.artistIds ? `&seed_artists=${seed.artistIds}` : ''}`
120
- const res = await player.aqua.resolve({
121
- query: seedQuery,
99
+ if (!trackId && !isrc && seed.title) {
100
+ const searchRes = await player.aqua.resolve({
101
+ query: `${seed.author ? `${seed.author} - ` : ''}${seed.title}`,
122
102
  source: 'spsearch',
123
103
  requester
124
104
  })
105
+ const foundTrack = searchRes?.tracks?.[0]
106
+ if (foundTrack) {
107
+ trackId = foundTrack.identifier !== 'local' ? foundTrack.identifier : null
108
+ isrc = foundTrack.isrc || null
109
+ }
110
+ }
111
+
112
+ if (!trackId && !isrc) return null
113
+
114
+ let query
115
+ if (isrc) {
116
+ query = `sprec:mix:isrc:${isrc}`
117
+ } else {
118
+ query = `sprec:seed_tracks=${trackId}`
119
+ }
120
+
121
+ let res = await player.aqua.resolve({
122
+ query,
123
+ requester
124
+ })
125
+
126
+ if (!res?.tracks?.length && isrc && trackId) {
127
+ res = await player.aqua.resolve({
128
+ query: `sprec:seed_tracks=${trackId}`,
129
+ requester
130
+ })
131
+ }
125
132
 
126
- const candidates = res?.tracks || []
127
- if (!candidates.length) return null
133
+ const candidates = res?.tracks || []
134
+ if (!candidates.length) return null
128
135
 
129
- const seen = new Set(excludedIds)
130
- const prevId = player.current?.identifier
131
- if (prevId) seen.add(prevId)
136
+ const seen = new Set(excludedIds)
137
+ const prevId = player.current?.identifier
138
+ if (prevId) seen.add(prevId)
132
139
 
133
- const out = []
134
- for (const t of candidates) {
135
- if (seen.has(t.identifier)) continue
136
- seen.add(t.identifier)
137
- t.pluginInfo = {
138
- ...(t.pluginInfo || {}),
139
- clientData: { fromAutoplay: true }
140
- }
141
- out.push(t)
142
- if (out.length === MAX_SP_RESULTS) break
140
+ const out = []
141
+ for (const t of candidates) {
142
+ if (seen.has(t.identifier)) continue
143
+ seen.add(t.identifier)
144
+ t.pluginInfo = {
145
+ ...(t.pluginInfo || {}),
146
+ clientData: { fromAutoplay: true }
143
147
  }
144
-
145
- return out.length ? out : null
146
- } catch (err) {
147
- console.error('spAutoPlay error:', err)
148
- return null
148
+ out.push(t)
149
149
  }
150
+
151
+ return out.length ? out : null
150
152
  }
151
153
 
152
154
  module.exports = {
153
155
  scAutoPlay,
154
- spAutoPlay,
155
- setSharedAgent
156
+ spAutoPlay
156
157
  }