Remove common consent overlays

This commit is contained in:
2026-05-16 22:32:30 -07:00
parent 62cd3e9509
commit 73b5313a0c
2 changed files with 125 additions and 3 deletions

View File

@@ -22,6 +22,68 @@ const VIEWPORT = {
height: 768
};
const COMMON_ANNOYANCE_SELECTORS = [
"[id^=\"sp_message_container_\"]",
"iframe[id^=\"sp_message_iframe_\"]",
"iframe[title*=\"consent\" i]",
"iframe[title*=\"privacy manager\" i]",
"#onetrust-consent-sdk",
"#onetrust-banner-sdk",
"#didomi-host",
"#qc-cmp2-container",
".qc-cmp2-container",
"#CybotCookiebotDialog",
".iubenda-cs-container",
"#cmpwrapper",
"[id^=\"cmpbox\"]",
".fc-consent-root",
".fc-dialog-container",
"[aria-modal=\"true\"][id*=\"consent\" i]",
"[aria-modal=\"true\"][id*=\"cookie\" i]",
"[role=\"dialog\"][aria-label*=\"cookie\" i]",
"[role=\"dialog\"][aria-label*=\"consent\" i]",
"[id*=\"cookie-banner\" i]",
"[class*=\"cookie-banner\" i]",
"[id*=\"cookie-consent\" i]",
"[class*=\"cookie-consent\" i]",
"[id*=\"cookie-notice\" i]",
"[class*=\"cookie-notice\" i]",
"[id*=\"cookie-popup\" i]",
"[class*=\"cookie-popup\" i]",
"[id*=\"adblock\" i]",
"[class*=\"adblock\" i]",
"[id*=\"ad-block\" i]",
"[class*=\"ad-block\" i]"
];
const COMMON_ANNOYANCE_ROOT_CLASSES = [
"sp-message-open",
"didomi-popup-open",
"qc-cmp-ui-showing",
"ot-sdk-show-settings",
"iubenda-cs-visible"
];
const COMMON_ANNOYANCE_CSS = `
${COMMON_ANNOYANCE_SELECTORS.join(",\n")} {
display: none !important;
visibility: hidden !important;
pointer-events: none !important;
}
html.sp-message-open,
body.sp-message-open,
html.didomi-popup-open,
body.didomi-popup-open,
html.qc-cmp-ui-showing,
body.qc-cmp-ui-showing,
html.iubenda-cs-visible,
body.iubenda-cs-visible {
overflow: auto !important;
position: static !important;
}
`;
export { DEFAULT_USER_AGENT, defaultArchivePath };
// ---------------------------------------------------------------------------
@@ -1176,9 +1238,10 @@ async function setupRequestBlocking(page, sourceHostname) {
}
async function injectCosmeticFilters(page, hostname) {
if (!privacyFiltersAvailable || filterRules.cosmeticRules.length === 0) return;
const lines = getCosmeticCssForHostname(filterRules, hostname);
const lines = [COMMON_ANNOYANCE_CSS];
if (privacyFiltersAvailable && filterRules.cosmeticRules.length > 0) {
lines.push(...getCosmeticCssForHostname(filterRules, hostname));
}
if (lines.length > 0) {
try {
await page.addStyleTag({ content: lines.join("\n") });
@@ -1188,6 +1251,42 @@ async function injectCosmeticFilters(page, hostname) {
}
}
async function removeCommonAnnoyances(page) {
try {
await page.evaluate(({ selectors, rootClasses }) => {
for (const selector of selectors) {
try {
document.querySelectorAll(selector).forEach((element) => element.remove());
} catch {
// Ignore selectors unsupported by the current browser.
}
}
for (const root of [document.documentElement, document.body].filter(Boolean)) {
root.classList.remove(...rootClasses);
root.removeAttribute("data-previous-scroll-y");
const overflow = root.style.overflow || "";
const position = root.style.position || "";
if (/hidden|clip/i.test(overflow)) {
root.style.removeProperty("overflow");
}
if (/fixed/i.test(position)) {
root.style.removeProperty("position");
root.style.removeProperty("top");
root.style.removeProperty("left");
root.style.removeProperty("right");
}
}
}, {
selectors: COMMON_ANNOYANCE_SELECTORS,
rootClasses: COMMON_ANNOYANCE_ROOT_CLASSES
});
} catch {
// Ignore cleanup failures; the archive is still useful.
}
}
const GM_MOCK = `
if (typeof GM === "undefined") {
window.GM = {
@@ -1320,6 +1419,7 @@ export async function renderPage(sourceUrl, options = {}) {
await page.waitForTimeout(userscriptDelay);
await waitForNetworkIdle(page);
await removeCommonAnnoyances(page);
await snapshotLoadedResourceUrls(page);
await snapshotRuntimeStyles(page);

View File

@@ -78,6 +78,28 @@ test("applies cosmetic filters with domain exceptions and skips unsupported proc
assert.match(getCosmeticCssForHostname(rules, "foo.com").join("\n"), /\.adguard/);
});
test("renderPage removes common cookie consent overlays before snapshot", async () => {
const html = `<!doctype html>
<html class="js sp-message-open" style="overflow: hidden;">
<body class="didomi-popup-open" style="overflow: hidden;">
<main>Article text</main>
<div id="sp_message_container_123" role="dialog" aria-modal="true">
<iframe id="sp_message_iframe_123" title="SP Consent Message" srcdoc="<p>Cookies on FT Sites</p>"></iframe>
</div>
</body>
</html>`;
const rendered = await renderPage(`data:text/html,${encodeURIComponent(html)}`, {
userscriptDelay: 0
});
assert.match(rendered, /Article text/);
assert.doesNotMatch(rendered, /sp_message_container_123/);
assert.doesNotMatch(rendered, /sp_message_iframe_123/);
assert.doesNotMatch(rendered, /<html[^>]*class="[^"]*sp-message-open/i);
assert.doesNotMatch(rendered, /<body[^>]*class="[^"]*didomi-popup-open/i);
});
test("renderPage serializes CSSOM-inserted style rules", async () => {
const html = `<!doctype html>
<html>