fix: CDX via Backend-Proxy /cdx statt Browser-fetch
This commit is contained in:
@@ -13,52 +13,14 @@ function getDomain(url) {
|
||||
catch { return url; }
|
||||
}
|
||||
|
||||
// Wayback CDX – direkt im Browser
|
||||
async function searchWayback(targetUrl) {
|
||||
const cdx = `https://web.archive.org/cdx/search/cdx?url=${encodeURIComponent(targetUrl)}&output=json&limit=1&fl=timestamp&filter=statuscode:200&fastLatest=true`;
|
||||
let res;
|
||||
try {
|
||||
// Ohne custom headers – minimaler Request damit CORS-Preflight entfällt
|
||||
res = await fetch(cdx);
|
||||
} catch (e) {
|
||||
throw new Error('Netzwerkfehler: ' + e.message);
|
||||
}
|
||||
if (!res.ok) throw new Error(`CDX ${res.status}`);
|
||||
const data = await res.json();
|
||||
if (!Array.isArray(data) || data.length < 2 || !data[1]?.[0]) return null;
|
||||
return `https://web.archive.org/web/${data[1][0]}/${targetUrl}`;
|
||||
}
|
||||
|
||||
// Wayback Save + CDX-Polling
|
||||
async function saveAndPollWayback(targetUrl, onStatus) {
|
||||
// Save via no-cors (kein lesbarer Response, aber Archivierung wird getriggert)
|
||||
try {
|
||||
fetch(`https://web.archive.org/save/${targetUrl}`, {
|
||||
method: 'GET',
|
||||
mode: 'no-cors',
|
||||
}).catch(() => {});
|
||||
} catch {}
|
||||
|
||||
// CDX pollen: 8x alle 5s = max 40s
|
||||
for (let i = 0; i < 8; i++) {
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
onStatus(`Warte auf Snapshot... (${(i + 1) * 5}s)`);
|
||||
try {
|
||||
const url = await searchWayback(targetUrl);
|
||||
if (url) return url;
|
||||
} catch {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function PaywallKiller() {
|
||||
const [inputUrl, setInputUrl] = useState('');
|
||||
const [status, setStatus] = useState('idle');
|
||||
const [statusMsg, setStatusMsg] = useState('');
|
||||
const [waybackUrl, setWaybackUrl] = useState('');
|
||||
const [wasCreated, setWasCreated] = useState(false);
|
||||
const [errMsg, setErrMsg] = useState('');
|
||||
const [pdfLoading, setPdfLoading] = useState(false);
|
||||
const [inputUrl, setInputUrl] = useState('');
|
||||
const [status, setStatus] = useState('idle');
|
||||
const [statusMsg, setStatusMsg] = useState('');
|
||||
const [waybackUrl, setWaybackUrl] = useState('');
|
||||
const [wasCreated, setWasCreated] = useState(false);
|
||||
const [errMsg, setErrMsg] = useState('');
|
||||
const [pdfLoading, setPdfLoading] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
function getTargetUrl() {
|
||||
@@ -66,6 +28,31 @@ export default function PaywallKiller() {
|
||||
return url.startsWith('http') ? url : 'https://' + url;
|
||||
}
|
||||
|
||||
// CDX-Suche über Backend-Proxy (umgeht CORS/Origin-Problem der PWA)
|
||||
async function searchWayback(targetUrl) {
|
||||
const data = await api(`/tools/paywallkiller/cdx?url=${encodeURIComponent(targetUrl)}`, { method: 'GET' });
|
||||
return data.found ? data.waybackUrl : null;
|
||||
}
|
||||
|
||||
// Save via Browser (no-cors, fire-and-forget), dann CDX-Polling via Backend
|
||||
async function saveAndPoll(targetUrl) {
|
||||
// Save-Request abschießen (Browser, kein CORS-Response nötig)
|
||||
try {
|
||||
fetch(`https://web.archive.org/save/${targetUrl}`, { mode: 'no-cors' }).catch(() => {});
|
||||
} catch {}
|
||||
|
||||
// CDX pollen via Backend-Proxy
|
||||
for (let i = 0; i < 8; i++) {
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
setStatusMsg(`Warte auf Snapshot... (${(i + 1) * 5}s)`);
|
||||
try {
|
||||
const url = await searchWayback(targetUrl);
|
||||
if (url) return url;
|
||||
} catch {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function handleCheck() {
|
||||
if (!inputUrl.trim()) return;
|
||||
const targetUrl = getTargetUrl();
|
||||
@@ -76,18 +63,16 @@ export default function PaywallKiller() {
|
||||
setWasCreated(false);
|
||||
|
||||
try {
|
||||
// Schritt 1: vorhandenen Snapshot suchen
|
||||
const existing = await searchWayback(targetUrl);
|
||||
if (existing) {
|
||||
setWaybackUrl(existing);
|
||||
setStatus('done');
|
||||
return;
|
||||
}
|
||||
|
||||
// Schritt 2: Kein Snapshot → neu erstellen + pollen
|
||||
// Kein Snapshot → archivieren
|
||||
setStatus('saving');
|
||||
setStatusMsg('Kein Snapshot gefunden – archiviere jetzt...');
|
||||
const newUrl = await saveAndPollWayback(targetUrl, msg => setStatusMsg(msg));
|
||||
setStatusMsg('Kein Snapshot – archiviere jetzt...');
|
||||
const newUrl = await saveAndPoll(targetUrl);
|
||||
if (newUrl) {
|
||||
setWaybackUrl(newUrl);
|
||||
setWasCreated(true);
|
||||
@@ -185,7 +170,6 @@ export default function PaywallKiller() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Wayback-Ergebnis */}
|
||||
{isDone && (
|
||||
<div style={{ ...S.card, borderColor: `${C.success}55`, marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
|
||||
@@ -209,19 +193,17 @@ export default function PaywallKiller() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Kein Snapshot erstellt */}
|
||||
{status === 'notfound' && (
|
||||
<div style={{ ...S.card, borderColor: `${C.error}44`, marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span>📭</span>
|
||||
<span style={{ color: C.error, fontFamily: 'monospace', fontSize: 12 }}>
|
||||
Archivierung fehlgeschlagen – {getDomain(inputUrl)} blockiert möglicherweise die Wayback Machine.
|
||||
Kein Snapshot gefunden – {getDomain(inputUrl)} blockiert möglicherweise die Wayback Machine.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* archive.ph – immer nach Suche anzeigen */}
|
||||
{hasResult && archivePhUrl && (
|
||||
<div style={{ ...S.card, borderColor: 'rgba(255,255,255,0.1)', marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
|
||||
@@ -249,7 +231,7 @@ export default function PaywallKiller() {
|
||||
<div style={{ ...S.head, marginBottom: 10 }}>SO FUNKTIONIERT ES</div>
|
||||
{[
|
||||
['1', 'URL einfügen (Long-Press → Einfügen)'],
|
||||
['2', 'Wayback Machine wird direkt im Browser durchsucht'],
|
||||
['2', 'Wayback Machine wird serverseitig durchsucht'],
|
||||
['3', 'Falls kein Snapshot: Artikel wird automatisch archiviert'],
|
||||
['4', 'Snapshot öffnen oder als PDF speichern'],
|
||||
].map(([num, text]) => (
|
||||
|
||||
Reference in New Issue
Block a user