From c75c488d3b35b70837743dfea5c99506cbabc87e Mon Sep 17 00:00:00 2001 From: Dicken Date: Fri, 12 Jun 2026 12:10:52 +0200 Subject: [PATCH] fix: wayback-save fire-and-forget + CDX polling statt Body-Wait --- backend/src/tools/paywallkiller/routes.js | 78 ++++++++++++++++------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/backend/src/tools/paywallkiller/routes.js b/backend/src/tools/paywallkiller/routes.js index 3d260fb..e93be60 100644 --- a/backend/src/tools/paywallkiller/routes.js +++ b/backend/src/tools/paywallkiller/routes.js @@ -259,7 +259,7 @@ router.get('/wayback', authenticate, async (req, res) => { }); // ── POST /api/tools/paywallkiller/wayback-save ──────────────────────────── -// Erstellt einen neuen Wayback-Snapshot und wartet auf das Ergebnis +// Schießt Save-Request ab (fire-and-forget), pollt dann CDX auf Ergebnis router.post('/wayback-save', authenticate, async (req, res) => { const { url } = req.body; if (!url || typeof url !== 'string') return res.status(400).json({ error: 'url fehlt' }); @@ -267,33 +267,67 @@ router.post('/wayback-save', authenticate, async (req, res) => { let targetUrl = url.trim(); if (!targetUrl.startsWith('http')) targetUrl = 'https://' + targetUrl; - // Save API aufrufen: GET https://web.archive.org/save/URL - // Antwort: 302 Redirect auf https://web.archive.org/web/TIMESTAMP/URL - try { - const saveUrl = `https://web.archive.org/save/${targetUrl}`; - const saveResult = await fetchPage(saveUrl); // fetchPage folgt Redirects + const https = require('https'); - // Nach Redirect landet man auf web.archive.org/web/TIMESTAMP/URL - const final = saveResult.finalUrl || ''; - const match = final.match(/web\.archive\.org\/web\/(\d{14})\//); - if (match) { - return res.json({ success: true, waybackUrl: final, timestamp: match[1] }); + // ── Hilfsfunktion: CDX prüfen ────────────────────────────────────────── + async function checkCdx() { + const cdxUrl = `https://web.archive.org/cdx/search/cdx?url=${encodeURIComponent(targetUrl)}&output=json&limit=1&fl=timestamp&filter=statuscode:200&fastLatest=true`; + try { + const r = await fetchPage(cdxUrl); + if (r.statusCode === 200 && r.body) { + const data = JSON.parse(r.body); + if (Array.isArray(data) && data.length >= 2 && data[1]?.[0]) { + return `https://web.archive.org/web/${data[1][0]}/${targetUrl}`; + } + } + } catch {} + return null; + } + + // ── Save-Request fire-and-forget (kein Warten auf Body) ─────────────── + function fireSaveRequest() { + return new Promise((resolve) => { + const saveUrl = new URL(`https://web.archive.org/save/${targetUrl}`); + const req = https.get({ + hostname: saveUrl.hostname, + path: saveUrl.pathname + saveUrl.search, + headers: { + 'User-Agent': 'Mozilla/5.0 (compatible; WaybackSave/1.0)', + 'Accept': 'text/html', + }, + timeout: 8000, + }, (res) => { + // Nur Headers lesen, Body sofort verwerfen + const location = res.headers.location || ''; + res.resume(); // Body ignorieren + resolve(location); + }); + req.on('error', () => resolve('')); + req.on('timeout', () => { req.destroy(); resolve(''); }); + }); + } + + try { + // Save abschießen + const location = await fireSaveRequest(); + + // Direkt aus Location-Header auslesen wenn vorhanden + const directMatch = location.match(/\/web\/(\d{14})\//); + if (directMatch) { + const waybackUrl = location.startsWith('http') ? location : `https://web.archive.org${location}`; + return res.json({ success: true, waybackUrl, timestamp: directMatch[1] }); } - // Fallback: CDX nochmal prüfen (Save kann asynchron sein) - await new Promise(r => setTimeout(r, 3000)); - const cdxUrl = `https://web.archive.org/cdx/search/cdx?url=${encodeURIComponent(targetUrl)}&output=json&limit=1&fl=timestamp&filter=statuscode:200&fastLatest=true`; - const cdxResult = await fetchPage(cdxUrl); - if (cdxResult.statusCode === 200) { - let data; - try { data = JSON.parse(cdxResult.body); } catch { data = null; } - if (Array.isArray(data) && data.length >= 2 && data[1]?.[0]) { - const timestamp = data[1][0]; - return res.json({ success: true, waybackUrl: `https://web.archive.org/web/${timestamp}/${targetUrl}`, timestamp }); + // Polling: bis zu 6x alle 5s CDX abfragen (max 30s warten) + for (let i = 0; i < 6; i++) { + await new Promise(r => setTimeout(r, 5000)); + const found = await checkCdx(); + if (found) { + return res.json({ success: true, waybackUrl: found }); } } - return res.status(502).json({ error: 'Snapshot konnte nicht erstellt werden. Die Seite blockiert möglicherweise die Wayback Machine.' }); + return res.status(502).json({ error: 'Archivierung läuft noch oder wurde blockiert. Versuche es in einer Minute erneut.' }); } catch (err) { return res.status(500).json({ error: 'Save fehlgeschlagen: ' + err.message }); }