feat: MakerWorld Raw-Fetch-Diagnose vor Puppeteer-Fallback

This commit is contained in:
2026-07-11 09:08:43 +02:00
parent 65041c0cca
commit 9f1dd4e3b8

View File

@@ -110,6 +110,33 @@ function mapStatisticalData(parsed) {
};
}
// Diagnose/Fallback: Abruf OHNE Browser, nur reiner HTTP-fetch() mit dem
// übergebenen Cookie-String. Testet, ob ein reiner Cookie-Replay reicht, oder
// ob Cloudflare zusätzlich am TLS-Fingerprint der Verbindung erkennt, dass es
// kein "echter" Browser ist (dann hilft auch kein Puppeteer-Cookie-Inject).
async function tryRawFetch(userId, cookieString) {
try {
const res = await fetch(DATA_URL, {
headers: {
'Cookie': cookieString,
'User-Agent': USER_AGENT,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'de,en-US;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate',
},
});
console.log(`[MakerWorld:${userId}] Raw-Fetch-Test: HTTP ${res.status}`);
if (!res.ok) return null;
const html = await res.text();
const parsed = extractNextData(html);
console.log(`[MakerWorld:${userId}] Raw-Fetch-Test: __NEXT_DATA__ ${parsed ? 'gefunden ✓' : 'nicht gefunden (vermutlich Just-a-moment-Seite)'}`);
return parsed;
} catch (e) {
console.log(`[MakerWorld:${userId}] Raw-Fetch-Test fehlgeschlagen: ${e.message}`);
return null;
}
}
// ── Browser-Helfer ────────────────────────────────────────────────────────────
// Nach einem abgebrochenen Vorgang (Container-Neustart mitten im Betrieb,
// Absturz o.ä.) kann Chromium veraltete Sperrdateien im Profil hinterlassen —
@@ -475,17 +502,34 @@ 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)`);
const userId = req.user.id;
console.log(`[MakerWorld:${userId}] 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' });
}
const cache = getCache(userId);
// Erst den günstigen Weg testen: reiner HTTP-fetch() ohne Browser
const rawParsed = await tryRawFetch(userId, cookie.trim());
if (rawParsed) {
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);
const data = mapStatisticalData(rawParsed);
cache.data = data; cache.fetchedAt = Date.now(); cache.error = null;
console.log(`[MakerWorld:${userId}] Raw-Fetch erfolgreich, Puppeteer nicht nötig`);
return res.json({ data: cache.data, error: null, fetchedAt: cache.fetchedAt, needsCode: false, method: 'raw-fetch' });
} catch (e) {
console.error(`[MakerWorld:${req.user.id}] POST /cookie Exception: ${e.message}`);
console.log(`[MakerWorld:${userId}] Raw-Fetch lieferte Seite, aber Mapping fehlgeschlagen: ${e.message}`);
}
}
// Fallback: über Puppeteer ins persistente Profil einspielen
try {
await injectCookies(userId, cookie.trim());
const result = await fetchStatsViaBrowser(userId, true);
console.log(`[MakerWorld:${userId}] POST /cookie fertig (Puppeteer-Fallback): needsCode=${result.needsCode}, error=${result.error||'-'}`);
res.json({ ...result, method: 'puppeteer' });
} catch (e) {
console.error(`[MakerWorld:${userId}] POST /cookie Exception: ${e.message}`);
res.status(500).json({ error: e.message });
}
});