Adblocker using Easylist right from InjectJS! No other extensions required.
<all_urls>
(async function () {
const CACHE_KEY = "__injectjs_easylist_cache__";
const CACHE_TIME_KEY = "__injectjs_easylist_time__";
const ONE_DAY = 24 * 60 * 60 * 1000;
const domain = location.hostname.replace(/^www\./, "");
async function getCachedRules() {
const cached = JSON.parse(localStorage.getItem(CACHE_KEY) || "{}");
const lastUpdate = parseInt(localStorage.getItem(CACHE_TIME_KEY) || "0", 10);
if (Date.now() - lastUpdate < ONE_DAY && cached.network && cached.cosmetic) {
console.log(`✅ InjectJS Adblock: Using cached rules`);
return cached;
}
console.log("🔄 InjectJS Adblock: Fetching EasyList...");
const res = await fetch("https://easylist.to/easylist/easylist.txt");
const text = await res.text();
const processed = processEasyList(text);
localStorage.setItem(CACHE_KEY, JSON.stringify(processed));
localStorage.setItem(CACHE_TIME_KEY, Date.now().toString());
console.log(`✅ InjectJS Adblock: Updated cache`);
return processed;
}
function processEasyList(text) {
const network = new Set();
const cosmetic = {};
for (const line of text.split("\n")) {
if (line.startsWith("||") && line.includes("^")) {
const host = line.slice(2).split("^")[0].replace(/^www\./, "");
network.add(host);
} else if (line.includes("##")) {
const [ruleDomain, selector] = line.split("##");
const key = ruleDomain || "*";
if (!cosmetic[key]) cosmetic[key] = [];
cosmetic[key].push(selector.trim());
}
}
return { network, cosmetic };
}
function isAdUrl(url, adHosts) {
try {
const host = new URL(url).hostname.replace(/^www\./, "");
return adHosts.has(host) || [...adHosts].some(h => host.endsWith(h));
} catch {
return false;
}
}
const { network: adHosts, cosmetic: allCosmetic } = await getCachedRules();
// ===== Network Monkeypatch =====
const originalFetch = window.fetch;
window.fetch = async function (...args) {
if (isAdUrl(args[0], adHosts)) {
console.log("[InjectJS Adblock] Blocked fetch:", args[0]);
return new Response("", { status: 204 });
}
return originalFetch.apply(this, args);
};
const OriginalXHR = window.XMLHttpRequest;
window.XMLHttpRequest = function () {
const xhr = new OriginalXHR();
const origOpen = xhr.open;
xhr.open = function (method, url, ...rest) {
if (isAdUrl(url, adHosts)) {
console.log("[InjectJS Adblock] Blocked XHR:", url);
return;
}
return origOpen.call(this, method, url, ...rest);
};
return xhr;
};
const origCreate = document.createElement;
document.createElement = function (tag) {
const el = origCreate.call(this, tag);
if (tag === "script") {
const origSet = el.setAttribute;
el.setAttribute = function (name, value) {
if (name === "src" && isAdUrl(value, adHosts)) {
console.log("[InjectJS Adblock] Blocked Script:", value);
return;
}
return origSet.call(this, name, value);
};
}
return el;
};
// ===== Cosmetic Filtering Optimized =====
const activeRules = (allCosmetic[domain] || []).concat(allCosmetic["*"] || []);
const idSet = new Set();
const classSet = new Set();
const complexSelectors = [];
for (const sel of activeRules) {
if (/^#[A-Za-z0-9_-]+$/.test(sel)) {
idSet.add(sel.slice(1));
} else if (/^\.[A-Za-z0-9_-]+$/.test(sel)) {
classSet.add(sel.slice(1));
} else {
complexSelectors.push(sel);
}
}
const limitedComplex = complexSelectors.slice(0, 300);
function handleNode(node) {
if (!(node instanceof HTMLElement)) return;
if (node.id && idSet.has(node.id)) {
console.log("[InjectJS Adblock] Removed by ID:", node);
node.remove();
return;
}
for (const c of node.classList) {
if (classSet.has(c)) {
console.log("[InjectJS Adblock] Removed by Class:", node);
node.remove();
return;
}
}
if (limitedComplex.length) {
try {
if (node.matches(limitedComplex.join(","))) {
console.log("[InjectJS Adblock] Removed by Selector:", node);
node.remove();
}
} catch {}
}
}
// Initial pass
const allSelectors = [
...[...idSet].map(id => `#${id}`),
...[...classSet].map(c => `.${c}`),
...limitedComplex
].join(",");
if (allSelectors.trim()) {
document.querySelectorAll(allSelectors).forEach(el => {
console.log("[InjectJS Adblock] Removed initial:", el);
el.remove();
});
}
// MutationObserver (batched)
let queue = [];
let scheduled = false;
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
queue.push(...m.addedNodes);
}
if (!scheduled) {
scheduled = true;
requestAnimationFrame(() => {
const unique = [...new Set(queue)];
queue = [];
unique.forEach(handleNode);
scheduled = false;
});
}
});
observer.observe(document.documentElement, { childList: true, subtree: true });
console.log(`✅ InjectJS Adblock active: ${adHosts.size} hosts, ${idSet.size} IDs, ${classSet.size} classes, ${limitedComplex.length} complex selectors`);
})();
Install requires the InjectJS Chrome extension. Scripts run only on sites matching the pattern above. Review code before installing any community script.