Greasy Fork

Greasy Fork is available in English.

屏蔽广告弹窗

屏蔽网页广告弹窗并绕过检测机制

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         屏蔽广告弹窗
// @namespace    https://www.f2iclo.cn/
// @version      1.0.0
// @description  屏蔽网页广告弹窗并绕过检测机制
// @author       Quirrel-zh
// @supportURL   https://github.com/Quirrel-zh/removeuviewAD/issues
// @homepage     https://github.com/Quirrel-zh/removeuviewAD
// @match        https://uview-plus.jiangruyi.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  // 1. 立即设置 localStorage 来绕过检查(最早执行)
  if (window.localStorage) {
    const expireTime = Math.floor(Date.now() / 1000) + 43200;
    localStorage.setItem('adExpire2', expireTime.toString());
  }

  // 2. 阻止页面被隐藏 - 拦截 style.opacity 的设置
  function protectDocumentOpacity() {
    // 等待 DOM 加载
    if (document.documentElement) {
      const htmlElement = document.documentElement;
      const originalStyleSetter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'style')?.set;
      
      // 拦截 style.opacity 的设置
      Object.defineProperty(htmlElement.style, 'opacity', {
        set: function(value) {
          if (value === '0' || value === 0 || value === '0') {
            // 阻止设置为 0
            return;
          }
          // 使用 CSSStyleDeclaration 的原生方法
          this.setProperty('opacity', value);
        },
        get: function() {
          const value = this.getPropertyValue('opacity');
          return value || '1';
        },
        configurable: true
      });
    } else {
      // 如果 documentElement 还不存在,延迟执行
      setTimeout(protectDocumentOpacity, 0);
    }
  }
  
  // 立即尝试保护
  protectDocumentOpacity();
  
  // 监听 DOM 加载完成
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', protectDocumentOpacity);
  }

  // 3. 拦截 alert 函数,防止检测机制弹出警告
  const originalAlert = window.alert;
  window.alert = function() {
    // 只拦截包含特定关键词的 alert
    const args = Array.from(arguments);
    if (args.some(arg => typeof arg === 'string' && arg.includes('广告屏蔽器'))) {
      return;
    }
    return originalAlert.apply(this, arguments);
  };

  // 4. 阻止检测机制中的关键检查
  function blockDetection() {
    // 阻止 MutationObserver 检测
    const OriginalMutationObserver = window.MutationObserver;
    window.MutationObserver = function(callback) {
      const wrappedCallback = function(mutations, observer) {
        // 过滤掉对弹窗元素的检测
        const filteredMutations = mutations.filter(mutation => {
          if (mutation.type === 'childList') {
            const addedNodes = Array.from(mutation.addedNodes);
            return !addedNodes.some(node => {
              if (node.nodeType === 1) { // Element node
                return node.id === 'pleasePrNotCrack' || 
                       node.classList?.contains('v-modal') ||
                       node.classList?.contains('el-dialog__wrapper');
              }
              return false;
            });
          }
          return true;
        });
        if (filteredMutations.length > 0) {
          callback(filteredMutations, observer);
        }
      };
      return new OriginalMutationObserver(wrappedCallback);
    };
  }

  // 5. 移除或隐藏弹窗元素
  function removeAdDialog() {
    if (!document.body) {
      // 如果 body 还不存在,等待 DOM 加载
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', removeAdDialog);
      } else {
        setTimeout(removeAdDialog, 100);
      }
      return;
    }

    // 使用 MutationObserver 监听弹窗出现并立即移除
    const observer = new MutationObserver(function(mutations) {
      // 移除所有弹窗元素(除了假元素)
      document.querySelectorAll('.v-modal, .el-dialog__wrapper, #pleasePrNotCrack').forEach(el => {
        const rect = el.getBoundingClientRect();
        // 如果元素不在屏幕外很远的地方(假元素在 -9999px),则移除
        if (rect.left > -5000) {
          el.remove();
        }
      });
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // 6. 阻止相关的 API 请求(可选,如果需要完全阻止)
  function blockAdApi() {
    const originalFetch = window.fetch;
    window.fetch = function(...args) {
      const url = args[0];
      if (typeof url === 'string' && url.includes('uiadmin.net/api/v1/wxapp/ad')) {
        // 阻止广告相关的 API 请求
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({ code: 200, data: { isVip: true } }),
          text: () => Promise.resolve(JSON.stringify({ code: 200, data: { isVip: true } }))
        });
      }
      return originalFetch.apply(this, args);
    };

    // 拦截 axios 请求(如果使用 axios)
    if (window.axios) {
      const originalPost = window.axios.post;
      window.axios.post = function(...args) {
        const url = args[0];
        if (typeof url === 'string' && url.includes('uiadmin.net/api/v1/wxapp/ad')) {
          return Promise.resolve({
            data: { code: 200, data: { isVip: true } }
          });
        }
        return originalPost.apply(this, args);
      };
    }
  }

  // 7. 阻止定时器检测
  function blockIntervalCheck() {
    const originalSetInterval = window.setInterval;
    window.setInterval = function(callback, delay) {
      // 如果回调函数包含检测逻辑,则阻止执行
      const callbackStr = callback.toString();
      if (callbackStr.includes('checkDisplay') || 
          callbackStr.includes('checkVip') ||
          callbackStr.includes('pleasePrNotCrack')) {
        return null; // 返回 null 而不是定时器 ID
      }
      return originalSetInterval.apply(this, arguments);
    };
  }

  // 8. 创建假的弹窗元素来欺骗检测机制(如果检测机制需要元素存在)
  function createFakeDialog() {
    if (!document.body) {
      setTimeout(createFakeDialog, 100);
      return;
    }

    // 如果元素不存在,创建一个隐藏的假元素
    if (!document.getElementById('pleasePrNotCrack')) {
      const fakeDialog = document.createElement('div');
      fakeDialog.id = 'pleasePrNotCrack';
      fakeDialog.style.display = 'none';
      fakeDialog.style.visibility = 'hidden';
      fakeDialog.style.opacity = '0';
      fakeDialog.style.position = 'absolute';
      fakeDialog.style.left = '-9999px';
      fakeDialog.style.zIndex = '-9999';
      document.body.appendChild(fakeDialog);
    }

    // 确保 v-modal 和 el-dialog__wrapper 也存在但隐藏
    if (!document.querySelector('.v-modal')) {
      const fakeModal = document.createElement('div');
      fakeModal.className = 'v-modal';
      fakeModal.style.display = 'none';
      fakeModal.style.visibility = 'visible'; // 保持 visible 但 display 为 none
      fakeModal.style.position = 'absolute';
      fakeModal.style.left = '-9999px';
      fakeModal.style.zIndex = '2000'; // 正常的 z-index
      fakeModal.style.background = 'rgba(0, 0, 0, 0.5)'; // 正常的背景色
      document.body.appendChild(fakeModal);
    }

    if (!document.querySelector('.el-dialog__wrapper')) {
      const fakeWrapper = document.createElement('div');
      fakeWrapper.className = 'el-dialog__wrapper';
      fakeWrapper.style.display = 'none';
      fakeWrapper.style.visibility = 'visible';
      fakeWrapper.style.position = 'absolute';
      fakeWrapper.style.left = '-9999px';
      fakeWrapper.style.zIndex = '2001';
      document.body.appendChild(fakeWrapper);
    }
  }

  // 执行所有防护措施
  function initProtection() {
    blockDetection();
    removeAdDialog();
    blockAdApi();
    blockIntervalCheck();
    createFakeDialog();
    
    // 定期清理真实弹窗,但保留假元素
    setInterval(() => {
      if (document.body) {
        document.querySelectorAll('.v-modal, .el-dialog__wrapper, #pleasePrNotCrack').forEach(el => {
          const rect = el.getBoundingClientRect();
          // 如果元素不在屏幕外很远的地方(假元素在 -9999px),则移除
          if (rect.left > -5000) {
            el.remove();
          }
        });
      }
    }, 1000);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initProtection);
  } else {
    initProtection();
  }

})();