/* ===================================================================== Fehlt irgendein Bild oder eine eingebundene Datei? Der Link-Test (pruef-links.mjs) prüft . Dieser hier prüft, was die Seite selbst LÄDT: Bilder (, CSS-Hintergründe über inline style), das Social-Preview-Bild (og:image, twitter:image), Favicon und das PWA-Manifest. Eine fehlende Datei zeigt sich als leerer Kasten, kaputtes Vorschaubild beim Teilen oder fehlendem App-Symbol -- oft unbemerkt, weil die Seite sonst funktioniert. Gegen die echte Domain. ===================================================================== */ import { chromium } from "playwright"; const BASIS = "https://dogfather-universe.com"; const SEITEN = [ "/", "/dogfather.html", "/hasidog.html", "/manager.html", "/casper.html", "/vanvan.html", "/tt-muddi.html", "/zeitreise.html", "/streamer.html", "/community.html", "/stimmen.html", "/streamplan.html", "/team-modis.html", "/team-scouts.html", "/creator.html", "/werte.html", "/bewerben.html", "/kontakt.html", "/links.html", "/supporter.html", "/abonnieren.html", "/medien-dogfather.html", "/medien-hasidog.html", "/medien-casper.html", ]; const browser = await chromium.launch(); const ziele = new Map(); // url -> { typ, seiten:Set } const merke = (url, typ, seite) => { if (!ziele.has(url)) ziele.set(url, { typ, seiten: new Set() }); ziele.get(url).seiten.add(seite); }; for (const pfad of SEITEN) { const seite = await browser.newPage(); try { await seite.goto(BASIS + pfad, { waitUntil: "networkidle", timeout: 30000 }); const funde = await seite.evaluate(() => { const raus = []; /* Sichtbare Bilder (currentSrc löst srcset/lazy korrekt auf). */ for (const im of document.querySelectorAll("img")) { const s = im.currentSrc || im.src; if (s && !s.startsWith("data:")) raus.push({ url: s, typ: "img" }); } /* Social-Preview + Favicon + Manifest aus dem . */ const meta = (sel, attr) => document.querySelector(sel)?.getAttribute(attr); const og = meta('meta[property="og:image"]', "content"); if (og) raus.push({ url: og, typ: "og:image" }); const tw = meta('meta[name="twitter:image"]', "content"); if (tw) raus.push({ url: tw, typ: "twitter:image" }); const fav = meta('link[rel="icon"]', "href"); if (fav) raus.push({ url: fav, typ: "favicon" }); const man = meta('link[rel="manifest"]', "href"); if (man) raus.push({ url: man, typ: "manifest" }); return raus; }); for (const f of funde) { let url; try { url = new URL(f.url, BASIS + pfad); } catch { continue; } if (url.origin !== BASIS) continue; // nur eigene Assets merke(url.pathname, f.typ, pfad); } } catch (e) { console.log(` (Seite ${pfad} nicht ladbar: ${String(e.message).slice(0, 40)})`); } await seite.close(); } console.log(`\n${ziele.size} verschiedene eigene Ressourcen gesammelt. Jede einmal geprüft:\n`); const pruef = await browser.newPage(); let ok = 0; const fehlt = []; for (const [url, info] of [...ziele].sort()) { try { const a = await pruef.goto(BASIS + url, { waitUntil: "commit", timeout: 20000 }); const code = a ? a.status() : 0; if (code < 400) ok++; else fehlt.push({ url, typ: info.typ, code, seiten: [...info.seiten] }); } catch (e) { fehlt.push({ url, typ: info.typ, code: String(e.message).slice(0, 24), seiten: [...info.seiten] }); } } await browser.close(); console.log(`===== ${ok} Ressourcen vorhanden, ${fehlt.length} fehlen =====`); if (fehlt.length) { console.log("\nFehlende Dateien (Typ, Adresse -> Code, benutzt auf):"); for (const f of fehlt) console.log(` - [${f.typ}] ${f.url} -> ${f.code} (${f.seiten.slice(0, 3).join(", ")}${f.seiten.length > 3 ? " …" : ""})`); } process.exitCode = fehlt.length ? 1 : 0;