feat: MakerWorld Raw-Fetch-Diagnose vor Puppeteer-Fallback
This commit is contained in:
@@ -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 {
|
||||
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.log(`[MakerWorld:${userId}] Raw-Fetch lieferte Seite, aber Mapping fehlgeschlagen: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: über Puppeteer ins persistente Profil einspielen
|
||||
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);
|
||||
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:${req.user.id}] POST /cookie Exception: ${e.message}`);
|
||||
console.error(`[MakerWorld:${userId}] POST /cookie Exception: ${e.message}`);
|
||||
res.status(500).json({ error: e.message });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user