fix: full stderr logging per-line, scan embed page for GQL hash

- Log each Python stderr line separately (no 500-char truncation) so
  we can see exactly what's happening in the bundle scan
- Try embed page (open.spotify.com/embed/...) first for GQL hashes —
  focused app, fewer bundles, GQL chunks directly referenced
- Suppress noisy bundle-fetch errors to keep logs readable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-11 21:26:51 +02:00
1 parent 46eb8c826f
commit 06b78be199
2 files changed
+14 -8

No files matched your search

+1 -1
View File
@@ -359,7 +359,7 @@ async function _resolveSpotifyViaSpotdl(url) {
const cleanUrl = url.split('?')[0]; const cleanUrl = url.split('?')[0];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
execFile('python3', [scriptPath, cleanUrl], { timeout: 90000, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => { execFile('python3', [scriptPath, cleanUrl], { timeout: 90000, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
if (stderr?.trim()) console.log('[spotdl-py]', stderr.trim().slice(0, 500)); if (stderr?.trim()) stderr.trim().split('\n').forEach(l => console.log('[py]', l));
// Always try to parse stdout first — script outputs JSON even on error // Always try to parse stdout first — script outputs JSON even on error
const out = stdout?.trim(); const out = stdout?.trim();
if (out) { if (out) {
+13 -7
View File
@@ -67,8 +67,8 @@ def _scan_bundles(session, js_urls, need_totp, need_ops):
if h: if h:
gql_hashes[op] = h gql_hashes[op] = h
eprint(f'[spotify] GQL hash {op}: {h[:16]}...') eprint(f'[spotify] GQL hash {op}: {h[:16]}...')
except Exception as e: except Exception:
eprint(f'[spotify] bundle error ({u[-40:]}): {e}') pass # skip failed bundles silently
return totp_secret, totp_version, gql_hashes return totp_secret, totp_version, gql_hashes
def get_token_and_hashes(session, sp_type, sp_id): def get_token_and_hashes(session, sp_type, sp_id):
@@ -90,17 +90,23 @@ def get_token_and_hashes(session, sp_type, sp_id):
if not totp_secret: if not totp_secret:
raise Exception('TOTP secret not found') raise Exception('TOTP secret not found')
# Step 2: resource page — find GQL hash (lazy-loaded playlist/album/track chunk) # Step 2: try embed page — focused app, GQL chunks often directly referenced
if GQL_OP not in gql_hashes: if GQL_OP not in gql_hashes:
eprint(f'[spotify] fetching {sp_type} page for GQL hash...') for extra_url in [
f'https://open.spotify.com/embed/{sp_type}/{sp_id}?utm_source=generator',
f'https://open.spotify.com/{sp_type}/{sp_id}',
]:
eprint(f'[spotify] scanning {extra_url[:60]} for GQL hash...')
try: try:
page_url = f'https://open.spotify.com/{sp_type}/{sp_id}' page_html = session.get(extra_url, headers=page_headers, timeout=15).text
page_html = session.get(page_url, headers=page_headers, timeout=15).text
extra_js = _collect_js_urls(page_html, seen) extra_js = _collect_js_urls(page_html, seen)
_, _, extra_hashes = _scan_bundles(session, extra_js[:25], False, [GQL_OP]) eprint(f'[spotify] found {len(extra_js)} new JS URLs on that page')
_, _, extra_hashes = _scan_bundles(session, extra_js[:30], False, [GQL_OP])
gql_hashes.update(extra_hashes) gql_hashes.update(extra_hashes)
except Exception as e: except Exception as e:
eprint(f'[spotify] page scan error: {e}') eprint(f'[spotify] page scan error: {e}')
if GQL_OP in gql_hashes:
break
st = session.get('https://open.spotify.com/api/server-time', headers={ st = session.get('https://open.spotify.com/api/server-time', headers={
'Accept': 'application/json', 'Referer': 'https://open.spotify.com/', 'Accept': 'application/json', 'Referer': 'https://open.spotify.com/',