feat: MakerWorld ausfuehrliches Logging fuer Diagnose

This commit is contained in:
2026-07-11 08:58:32 +02:00
parent 1557959eb0
commit 65041c0cca

View File

@@ -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 });
}
});