您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
全広告スクリプト削除、画面表示後の<script>挿入ブロック、ページ内広告要素削除
// ==UserScript== // @name あにまん広告完全削除 // @version 1.0.1 // @description 全広告スクリプト削除、画面表示後の<script>挿入ブロック、ページ内広告要素削除 // @match *://bbs.animanch.com/* // @run-at document-start // @grant none // @license MIT // @namespace https://greasyfork.org/users/1494168 // ==/UserScript== (function() { 'use strict'; // ──────────────────────────────────────────────── // ホワイトリスト判定:Twitter埋め込み用iframe/script // ──────────────────────────────────────────────── function isTwitterIframe(node) { return node.tagName === 'IFRAME' && node.id && node.id.toLowerCase().includes('twitter'); } function isTwitterScript(node) { return node.tagName === 'SCRIPT' && node.src && node.src.includes('platform.twitter.com/widgets.js'); } // ──────────────────────────────────────────────── // RemoveAd 関数:ページ内の広告要素を削除 // ──────────────────────────────────────────────── function RemoveAd() { if (!window.jQuery) return; const $ = window.jQuery; // ID/Classが"AD"で始まる要素 $('[id^="AD"], [class^="AD"]').remove(); // div.inner $('div.inner').remove(); // div[data-cptid] $('div[data-cptid]').remove(); // #reslist下の不正 iframe $('#reslist').find('iframe[id^="gnpbad_"]').closest('li').remove(); } // ──────────────────────────────────────────────── // 1. document-start:既存広告<script>/<iframe>を即削除 // ──────────────────────────────────────────────── const AD_PATTERNS = [ /adrecover\.com/, /delivery\.adrecover\.com/, /geniee\.jp/, /cpt\.geniee\.jp/, /iago\.min\.js/, /pubmatic\.com/, /rtbhouse/, /onetag-sys\.com/, /undertone\.com/, /rubiconproject\.com/, /criteo\.com/, /doubleclick\.net/, /g\.doubleclick\.net/, /googletagmanager\.com/, /prebid-v\d+/, /dmp\.im-apps\.net/, /ads\.pubmatic\.com/, /authorizedvault\.com/ ]; function isAdNode(node) { if (!node.tagName) return false; // Twitter関連は除外 if (isTwitterIframe(node) || isTwitterScript(node)) return false; const tag = node.tagName.toUpperCase(); if (tag !== 'SCRIPT' && tag !== 'IFRAME') return false; const src = node.src || node.getAttribute('src') || ''; return AD_PATTERNS.some(rx => rx.test(src)); } // 既存の<script>/<iframe>を即座に削除 document.querySelectorAll('script, iframe').forEach(el => { if (isAdNode(el)) el.remove(); }); // 動的挿入の広告ノードも監視して削除 const adObserver = new MutationObserver(records => { for (const rec of records) { rec.addedNodes.forEach(node => { if (node.nodeType === 1 && isAdNode(node)) { node.remove(); } }); } // ページ内広告要素も合わせて削除 RemoveAd(); }); adObserver.observe(document.documentElement, { childList: true, subtree: true }); // <script>/<iframe> の src 設定自体をブロック const origCreate = Document.prototype.createElement; Document.prototype.createElement = function(tagName, options) { const el = origCreate.call(this, tagName, options); const tn = tagName.toLowerCase(); if (tn === 'script' || tn === 'iframe') { const desc = Object.getOwnPropertyDescriptor(el.__proto__, 'src'); Object.defineProperty(el, 'src', { get: desc.get, set(value) { // Twitter関連スクリプトは許可、それ以外の広告URLを阻止 if (!isTwitterIframe(el) && !isTwitterScript(el) && AD_PATTERNS.some( rx => rx.test(value))) { console.debug('Blocked ad src:', value); return; } return desc.set.call(this, value); }, configurable: true, enumerable: true }); } return el; }; // appendChild/insertBefore も広告ノードは阻止 [Element.prototype, Node.prototype].forEach(proto => { ['appendChild', 'insertBefore'].forEach(fnName => { const orig = proto[fnName]; proto[fnName] = function(node, ref) { if (node.nodeType === 1 && isAdNode(node)) { console.debug(`Blocked ad node on ${fnName}`, node); return node; } return orig.call(this, node, ref); }; }); }); // ──────────────────────────────────────────────── // 2. document-end:動的<script>挿入をブロック&RemoveAd実行 // ──────────────────────────────────────────────── function onDocumentEnd() { // ページ内広告要素を一度削除 RemoveAd(); // 動的に追加される<script>を監視して削除 const obs = new MutationObserver(records => { for (const rec of records) { rec.addedNodes.forEach(node => { if (node.nodeType !== 1) return; // Twitter関連スクリプトはそのまま、その他<script>は削除 if (node.tagName === 'SCRIPT' && !isTwitterScript(node)) { node.remove(); } // 子孫に<script>を含む場合はまとめて削除 else if (node.getElementsByTagName('script').length) { node.remove(); } }); } // 同時に広告要素も削除 RemoveAd(); }); obs.observe(document.documentElement, { childList: true, subtree: true }); // innerHTML/insertAdjacentHTML/document.write系での<script>混入も除去 const sanitize = html => String(html).replace(/<script[\s\S]*?<\/script>/gi, ''); const htmlDesc = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML'); Object.defineProperty(Element.prototype, 'innerHTML', { set(value) { return htmlDesc.set.call(this, sanitize(value)); }, get() { return htmlDesc.get.call(this); }, configurable: true, enumerable: true }); const origIAH = Element.prototype.insertAdjacentHTML; Element.prototype.insertAdjacentHTML = function(pos, html) { return origIAH.call(this, pos, sanitize(html)); }; ['write', 'writeln'].forEach(fn => { const orig = Document.prototype[fn]; Document.prototype[fn] = function(...args) { return orig.call(this, args.map(a => sanitize(a)).join('')); }; }); // ボタンを正常な位置へ const btn = document.getElementById('fixbtn'); if (btn) { btn.style.setProperty('bottom', '20px', 'important'); } } if (document.readyState === 'loading') { window.addEventListener('DOMContentLoaded', onDocumentEnd); } else { onDocumentEnd(); } })();