@browserless/goto
Version:
Navigate to web pages with built-in ad blocking, device emulation, and optimized loading for faster automation.
110 lines (93 loc) • 3.26 kB
JavaScript
const { PuppeteerBlocker } = require('@ghostery/adblocker-puppeteer')
const path = require('path')
const fs = require('fs')
const debug = require('debug-logfmt')('browserless:goto:adblock')
const engine = PuppeteerBlocker.deserialize(
new Uint8Array(fs.readFileSync(path.resolve(__dirname, './engine.bin')))
)
engine.on('request-blocked', ({ url }) => debug('block', url))
engine.on('request-redirected', ({ url }) => debug('redirect', url))
/**
* autoconsent.playwright.js is the only browser-injectable IIFE bundle in the package.
* It is not in the package's "exports" map, so pin @duckduckgo/autoconsent with ~ to
* avoid breakage from internal restructuring on minor/patch bumps.
*/
const autoconsentPlaywrightScript = fs.readFileSync(
path.resolve(
path.dirname(require.resolve('@duckduckgo/autoconsent')),
'autoconsent.playwright.js'
),
'utf8'
)
/* Configuration passed to autoconsent's `initResp` message.
See https://github.com/duckduckgo/autoconsent/blob/main/api.md */
const autoconsentConfig = Object.freeze({
/* activate consent rule matching */
enabled: true,
/* automatically reject (opt-out) all cookies */
autoAction: 'optOut',
/* hide banners early via CSS before detection finishes */
enablePrehide: true,
/* apply CSS-only rules that hide popups lacking a reject button */
enableCosmeticRules: true,
/* skip bundled ABP/uBO cosmetic filter list (saves bundle size) */
enableFilterList: false,
/* how many times to retry CMP detection (~50 ms apart) */
detectRetries: 20,
logs: {
/* CMP detection / opt-out lifecycle events */
lifecycle: false,
/* individual rule step execution */
rulesteps: false,
/* eval snippet calls */
evals: false,
/* rule errors */
errors: false,
/* background ↔ content-script messages */
messages: false
}
})
const sendMessage = (page, message) =>
page
.evaluate(msg => {
if (window.autoconsentReceiveMessage) {
return window.autoconsentReceiveMessage(msg)
}
}, message)
.catch(() => {})
const setupAutoConsent = async page => {
if (page._autoconsentSetup) return
await page.exposeFunction('autoconsentSendMessage', async message => {
if (!message || typeof message !== 'object') return
if (message.type === 'init') {
return sendMessage(page, { type: 'initResp', config: autoconsentConfig })
}
if (message.type === 'eval') {
return sendMessage(page, { type: 'evalResp', id: message.id, result: false })
}
})
await page.evaluateOnNewDocument(autoconsentPlaywrightScript)
page._autoconsentSetup = true
}
const runAutoConsent = page => page.evaluate(autoconsentPlaywrightScript)
const enableBlockingInPage = (page, run, actionTimeout) => {
page.disableAdblock = () =>
engine
.disableBlockingInPage(page, { keepRequestInterception: true })
.then(() => debug('disabled'))
.catch(() => {})
return [
run({
fn: setupAutoConsent(page),
timeout: actionTimeout,
debug: 'autoconsent:setup'
}),
run({
fn: engine.enableBlockingInPage(page),
timeout: actionTimeout,
debug: 'adblock'
})
]
}
module.exports = { enableBlockingInPage, runAutoConsent }