'; };
right.appendChild(img);
}
async function scrapeCover(pageUrl) {
const res = await fetch(pageUrl, { credentials: "same-origin" });
if (!res.ok) throw new Error("fetch failed");
const html = await res.text();
const doc = new DOMParser().parseFromString(html, "text/html");
const og = doc.querySelector('meta[property="og:image"]')?.getAttribute("content");
if (og) return og;
const img =
doc.querySelector("article img") ||
doc.querySelector(".entry-content img") ||
doc.querySelector("img");
const src = img?.getAttribute("src") || img?.getAttribute("data-src");
if (src) return src;
throw new Error("no image found");
}
// limit concurrency so you don’t hammer the server
const queue = cards
.map(c => ({ card: c, page: c.getAttribute("data-page") }))
.filter(x => x.page);
const MAX = 4;
let i = 0;
async function worker() {
while (i No cover
';
}
}
}
for (let w = 0; w