diff --git a/backend/src/tools/paywallkiller/routes.js b/backend/src/tools/paywallkiller/routes.js index cc2c905..e38b3ff 100644 --- a/backend/src/tools/paywallkiller/routes.js +++ b/backend/src/tools/paywallkiller/routes.js @@ -229,4 +229,35 @@ router.post('/pdf', authenticate, async (req, res) => { } }); + +// ── GET /api/tools/paywallkiller/wayback?url=... ────────────────────────── +// Proxyt die Wayback CDX API – umgeht CORS/CSP Probleme im Browser +router.get('/wayback', authenticate, async (req, res) => { + const { url } = req.query; + if (!url || typeof url !== 'string') return res.status(400).json({ error: 'url Parameter fehlt' }); + + let targetUrl = url.trim(); + if (!targetUrl.startsWith('http')) targetUrl = 'https://' + targetUrl; + + 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 result = await fetchPage(cdxUrl); + if (result.statusCode !== 200) { + return res.status(502).json({ error: `Wayback API Fehler: ${result.statusCode}` }); + } + let data; + try { data = JSON.parse(result.body); } catch { return res.status(502).json({ error: 'Ungültige Wayback-Antwort' }); } + + // data = [["timestamp"],["20260608201434"]] oder [] wenn nichts gefunden + if (!Array.isArray(data) || data.length < 2 || !data[1]?.[0]) { + return res.json({ found: false }); + } + const timestamp = data[1][0]; + return res.json({ found: true, waybackUrl: `https://web.archive.org/web/${timestamp}/${targetUrl}` }); + } catch (err) { + return res.status(500).json({ error: 'Fehler: ' + err.message }); + } +}); + module.exports = router; diff --git a/frontend/src/tools/paywallkiller.jsx b/frontend/src/tools/paywallkiller.jsx index 6208c9a..cd1fac7 100644 --- a/frontend/src/tools/paywallkiller.jsx +++ b/frontend/src/tools/paywallkiller.jsx @@ -1,5 +1,5 @@ import { useState, useRef } from 'react'; -import { S } from '../lib.js'; +import { S, api } from '../lib.js'; const C = { accent: '#f59e0b', @@ -13,18 +13,6 @@ function getDomain(url) { catch { return url; } } -// Wayback CDX API – direkt im Browser (CORS: *) -async function checkWayback(targetUrl) { - const cdxUrl = `https://web.archive.org/cdx/search/cdx?url=${encodeURIComponent(targetUrl)}&output=json&limit=1&fl=timestamp&filter=statuscode:200&fastLatest=true`; - const res = await fetch(cdxUrl, { signal: AbortSignal.timeout(12000) }); - if (!res.ok) throw new Error(`CDX API Fehler: ${res.status}`); - const data = await res.json(); - if (!Array.isArray(data) || data.length < 2) return null; - const timestamp = data[1]?.[0]; - if (!timestamp) return null; - return `https://web.archive.org/web/${timestamp}/${targetUrl}`; -} - export default function PaywallKiller() { const [inputUrl, setInputUrl] = useState(''); const [status, setStatus] = useState('idle'); @@ -41,9 +29,8 @@ export default function PaywallKiller() { setErrMsg(''); setWaybackUrl(''); try { - const wb = await checkWayback(targetUrl); - setWaybackUrl(wb || ''); - // Immer "found" zeigen – Wayback-Treffer oder nicht, archive.ph Link immer anbieten + const data = await api(`/tools/paywallkiller/wayback?url=${encodeURIComponent(targetUrl)}`, { method: 'GET' }); + setWaybackUrl(data.found ? data.waybackUrl : ''); setStatus('done'); } catch (err) { setErrMsg(err.message || 'Fehler beim Suchen'); @@ -94,19 +81,6 @@ export default function PaywallKiller() { setTimeout(() => inputRef.current?.focus(), 50); } - function handlePaste() { - // Fokus ins Input setzen und nativen Paste auslösen – kein Permission-Dialog - const input = inputRef.current; - if (!input) return; - input.focus(); - // execCommand('paste') funktioniert auf Android ohne Clipboard-Permission - const ok = document.execCommand('paste'); - if (!ok) { - // Fallback: nur fokussieren, User kann selbst einfügen - input.select(); - } - } - const isChecking = status === 'checking'; const isDone = status === 'done'; const hasWayback = isDone && !!waybackUrl; @@ -131,24 +105,18 @@ export default function PaywallKiller() { {/* Eingabe */}