diff --git a/backend/src/tools/makerworld/routes.js b/backend/src/tools/makerworld/routes.js index af63603..ba1a8d9 100644 --- a/backend/src/tools/makerworld/routes.js +++ b/backend/src/tools/makerworld/routes.js @@ -254,36 +254,47 @@ async function attemptLogin(userId, browser, page) { async function fetchStatsViaBrowserInner(userId, forceRefresh) { const cache = getCache(userId); if (!forceRefresh && cache.data && (Date.now() - cache.fetchedAt) < CACHE_TTL_MS) { + console.log(`[MakerWorld:${userId}] Cache-Treffer, kein Neuabruf (forceRefresh=false)`); return { data: cache.data, error: null, fetchedAt: cache.fetchedAt, needsCode: false }; } if (pendingLoginByUser.has(userId)) { + console.log(`[MakerWorld:${userId}] Noch ein offener Login-Vorgang (wartet auf Code) — Abruf übersprungen`); return { data: cache.data, error: null, fetchedAt: cache.fetchedAt, needsCode: true }; } let browser; let page; try { + console.log(`[MakerWorld:${userId}] Abruf gestartet (forceRefresh=${forceRefresh})`); browser = await launchBrowser(userId); + console.log(`[MakerWorld:${userId}] Browser gestartet, öffne Seite`); page = await browser.newPage(); await page.setUserAgent(USER_AGENT); await page.setViewport({ width: 1366, height: 900 }); await page.goto(DATA_URL, { waitUntil: 'networkidle2', timeout: 45000 }); + console.log(`[MakerWorld:${userId}] Seite geladen: "${await page.title().catch(()=>'?')}" (${page.url()})`); // Bis zu 20 Sekunden Zeit geben, falls Cloudflare eine automatische // Managed-Challenge zeigt (löst sich bei echtem Chromium meist selbst) + let cfWaited = 0; for (let i = 0; i < 5 && await isCloudflareChallenge(page); i++) { + cfWaited += 4; + console.log(`[MakerWorld:${userId}] Cloudflare-Challenge erkannt, warte weiter (${cfWaited}s)...`); await new Promise(r => setTimeout(r, 4000)); } let parsed = await getNextDataFromPage(page); + console.log(`[MakerWorld:${userId}] __NEXT_DATA__ ${parsed ? 'gefunden' : 'NICHT gefunden'}`); if (!parsed && isLoginUrl(page.url())) { + console.log(`[MakerWorld:${userId}] Login-Seite erkannt (${page.url()}), versuche automatischen Login`); parsed = await attemptLogin(userId, browser, page); // wirft ggf. needsCode-Error } if (!parsed) { const debugTitle = await page.title().catch(() => '?'); const debugUrl = page.url(); + console.log(`[MakerWorld:${userId}] Fehlschlag — Seite: "${debugTitle}" (${debugUrl})`); await saveDebugScreenshot(userId, page).catch(() => {}); throw new Error(`__NEXT_DATA__ nicht gefunden — Seite: "${debugTitle}" (${debugUrl}). Debug-Screenshot verfügbar über GET /debug-screenshot`); } @@ -291,11 +302,14 @@ async function fetchStatsViaBrowserInner(userId, forceRefresh) { const data = mapStatisticalData(parsed); cache.data = data; cache.fetchedAt = Date.now(); cache.error = null; await browser.close(); + console.log(`[MakerWorld:${userId}] Erfolgreich: ${data.downloads} Downloads, ${data.likes} Likes`); return { data: cache.data, error: null, fetchedAt: cache.fetchedAt, needsCode: false }; } catch (e) { if (e.needsCode) { + console.log(`[MakerWorld:${userId}] Code-Eingabe erforderlich, Browser bleibt offen`); return { data: cache.data, error: null, fetchedAt: cache.fetchedAt, needsCode: true }; } + console.error(`[MakerWorld:${userId}] Fehler: ${e.message}`); if (browser) await browser.close().catch(() => {}); cache.error = e.message; return { data: cache.data, error: cache.error, fetchedAt: cache.fetchedAt, needsCode: false }; @@ -340,15 +354,21 @@ async function submitLoginCodeInner(userId, code) { } async function injectCookiesInner(userId, cookieString) { + console.log(`[MakerWorld:${userId}] Cookie-Injection gestartet (${cookieString.length} Zeichen)`); const cookies = cookieString.split(';').map(s => s.trim()).filter(Boolean).map(p => { const idx = p.indexOf('='); return { name: p.slice(0, idx), value: p.slice(idx + 1), domain: '.makerworld.com', path: '/' }; }); + console.log(`[MakerWorld:${userId}] ${cookies.length} Cookies geparst: ${cookies.map(c=>c.name).join(', ')}`); const browser = await launchBrowser(userId); + console.log(`[MakerWorld:${userId}] Browser für Cookie-Injection gestartet`); try { const page = await browser.newPage(); - await page.goto('https://makerworld.com', { waitUntil: 'domcontentloaded', timeout: 20000 }).catch(() => {}); + await page.goto('https://makerworld.com', { waitUntil: 'domcontentloaded', timeout: 20000 }).catch((e) => { + console.log(`[MakerWorld:${userId}] Navigation vor Cookie-Set fehlgeschlagen (ignoriert): ${e.message}`); + }); await page.setCookie(...cookies); + console.log(`[MakerWorld:${userId}] Cookies gesetzt, schließe Browser`); } finally { await browser.close(); } @@ -455,14 +475,17 @@ router.delete('/credentials', authenticate, (req, res) => { // Manueller Fallback: Cookie-String direkt ins eigene Profil einspielen router.post('/cookie', authenticate, async (req, res) => { const { cookie } = req.body; + console.log(`[MakerWorld:${req.user.id}] POST /cookie empfangen (${cookie?.length || 0} Zeichen)`); if (!cookie || typeof cookie !== 'string' || cookie.trim().length < 10) { return res.status(400).json({ error: 'Ungültiger Cookie-String' }); } try { await injectCookies(req.user.id, cookie.trim()); const result = await fetchStatsViaBrowser(req.user.id, true); + console.log(`[MakerWorld:${req.user.id}] POST /cookie fertig: needsCode=${result.needsCode}, error=${result.error||'-'}`); res.json(result); } catch (e) { + console.error(`[MakerWorld:${req.user.id}] POST /cookie Exception: ${e.message}`); res.status(500).json({ error: e.message }); } });