diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index 79d084f..f7c82a4 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -359,7 +359,7 @@ async function _resolveSpotifyViaSpotdl(url) { const cleanUrl = url.split('?')[0]; return new Promise((resolve, reject) => { 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 const out = stdout?.trim(); if (out) { diff --git a/backend/spotify_resolve.py b/backend/spotify_resolve.py index 84cfdcf..2b40302 100644 --- a/backend/spotify_resolve.py +++ b/backend/spotify_resolve.py @@ -67,8 +67,8 @@ def _scan_bundles(session, js_urls, need_totp, need_ops): if h: gql_hashes[op] = h eprint(f'[spotify] GQL hash {op}: {h[:16]}...') - except Exception as e: - eprint(f'[spotify] bundle error ({u[-40:]}): {e}') + except Exception: + pass # skip failed bundles silently return totp_secret, totp_version, gql_hashes 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: 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: - eprint(f'[spotify] fetching {sp_type} page for GQL hash...') - try: - page_url = f'https://open.spotify.com/{sp_type}/{sp_id}' - page_html = session.get(page_url, headers=page_headers, timeout=15).text - extra_js = _collect_js_urls(page_html, seen) - _, _, extra_hashes = _scan_bundles(session, extra_js[:25], False, [GQL_OP]) - gql_hashes.update(extra_hashes) - except Exception as e: - eprint(f'[spotify] page scan error: {e}') + 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: + page_html = session.get(extra_url, headers=page_headers, timeout=15).text + extra_js = _collect_js_urls(page_html, seen) + 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) + except Exception as 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={ 'Accept': 'application/json', 'Referer': 'https://open.spotify.com/',