N1 AD clearer

clean ad

// ==UserScript==
// @name         N1 AD clearer
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  clean ad
// @author       Beaverite
// @match        https://narrow.one/*
// @grant        GM_addStyle
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function () {
  'use strict';

  //u can complement
  const URL_PATTERNS = [
    'doubleclick\\.net',
    'googlesyndication',
    'adservice\\.google',
    'adsystem',
    'adserver',
    '/ads/',
    '/getad',
    'interstitial',
    'servead',
    '\\bad(s|vert).*\\.js',
    'rainbow-house\\.com\\.tw',
    'store\\.logitech\\.tw',
    'facebook\\.com',
    'youtube\\.com',
    'x\\.com',
    'instagram\\.com',
    'discord\\.com',
    'googletagmanager\\.com',
    'googletagservices\\.com',
    'google-analytics\\.com',
    'scorecardresearch\\.com',
    'zedo\\.com',
    'adnxs\\.com',
    'criteo\\.com',
    'taboola\\.com',
    'outbrain\\.com',
    'quantserve\\.com'
  ].map(s => new RegExp(s, 'i'));
  const NODE_SELECTORS = [
    'iframe[src*="ad"]',
    'iframe[src*="ads"]',
    '[class*="ad-"]',
    '[id*="ad-"]',
    '.ads',
    '.advert',
    '.overlay-ad',
    '.video-ad',
    '.interstitial',
  ];
  //

  const NODE_WHITELIST = [
    '.game-ui', '.hud', '#gameCanvas'
  ];
  function matchesBlockUrl(url) {
    if (!url) return false;
    return URL_PATTERNS.some(re => re.test(url));
  }
  function isWhitelisted(node) {
    if (!node || !node.matches) return false;
    return NODE_WHITELIST.some(s => node.matches(s));
  }
  const _origFetch = window.fetch;
  window.fetch = function (input, init) {
    const url = (typeof input === 'string') ? input : (input && input.url) || '';
    if (matchesBlockUrl(url)) {
      console.info('[AdBlocker] blocked fetch:', url);
      return Promise.reject(new DOMException('Blocked by userscript'));
    }
    return _origFetch.apply(this, arguments);
  };
  const _origXhrOpen = XMLHttpRequest.prototype.open;
  XMLHttpRequest.prototype.open = function (method, url) {
    if (matchesBlockUrl(url)) {
      console.info('[AdBlocker] blocking XHR open to', url);
      this.__blockByAdBlocker = true;
    }
    return _origXhrOpen.apply(this, arguments);
  };
  const _origXhrSend = XMLHttpRequest.prototype.send;
  XMLHttpRequest.prototype.send = function () {
    if (this.__blockByAdBlocker) {
      this.abort && this.abort();
      console.info('[AdBlocker] aborted XHR');
      return;
    }
    return _origXhrSend.apply(this, arguments);
  };
  const origOpen = window.open;
  window.open = function (url, name, specs) {
    if (matchesBlockUrl(url)) {
      console.info('[AdBlocker] blocked popup:', url);
      return null;
    }
    return origOpen.apply(this, arguments);
  };
  const origSetAttr = Element.prototype.setAttribute;
  Element.prototype.setAttribute = function (name, value) {
    if ((this.tagName === 'IFRAME' || this.tagName === 'FRAME') && name === 'src' && matchesBlockUrl(value)) {
      console.info('[AdBlocker] blocked iframe src set to', value);
      return;
    }
    return origSetAttr.apply(this, arguments);
  };
  function cleanNode(node) {
    if (!node || !(node instanceof Element)) return;
    if (isWhitelisted(node)) return;
    for (const sel of NODE_SELECTORS) {
      if (node.matches && node.matches(sel)) {
        console.info('[AdBlocker] removing node matching', sel);
        node.remove();
        return;
      }
    }
    node.querySelectorAll && node.querySelectorAll('iframe,frame').forEach(iframe => {
      const s = iframe.getAttribute && iframe.getAttribute('src');
      if (matchesBlockUrl(s)) {
        console.info('[AdBlocker] removing iframe with blocked src', s);
        iframe.remove();
      }
    });
  }
  const observer = new MutationObserver(muts => {
    for (const m of muts) {
      if (m.type === 'childList') {
        m.addedNodes && m.addedNodes.forEach(n => {
          if (n.nodeType === Node.ELEMENT_NODE) cleanNode(n);
        });
      } else if (m.type === 'attributes') {
        cleanNode(m.target);
      }
    }
  });
  function startObserver() {
    observer.observe(document.documentElement || document.body, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ['class', 'id', 'style', 'src']
    });
  }
  function initialSweep() {
    NODE_SELECTORS.forEach(sel => {
      document.querySelectorAll(sel).forEach(n => cleanNode(n));
    });
    document.querySelectorAll('iframe,frame').forEach(fr => {
      const s = fr.getAttribute && fr.getAttribute('src');
      if (matchesBlockUrl(s)) {
        console.info('[AdBlocker] initial removing iframe', s);
        fr.remove();
      }
    });
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => {
      initialSweep();
      startObserver();
    });
  } else {
    initialSweep();
    startObserver();
  }
  console.info('[AdBlocker] script loaded for narrow.one with extended rules');
})();