achabuhecha / 浮动广告屏蔽

// ==UserScript==
// @name          浮动广告屏蔽
// @name:zh       浮动广告屏蔽插件,用于屏蔽网页什么的浮动广告/图片
// @namespace         float_ad_blocker
// @version           2.2.6
// @description       Floating ad blocking plug-in, used to block floating ads/pictures on web pages
// @description:zh    浮动广告屏蔽插件,用于屏蔽网页什么的浮动广告/图片
// @author            coolhii
// @icon              data:image/png;base64,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
// @include           http://*/*
// @include           https://*/*
// @require           https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
// @grant             unsafeWindow
// @license           AGPL-3.0-only
// @charset          UTF-8
// @run-at            document-idle
// ==/UserScript==
(function () {
  'use strict'

  // 当前页面的主机名,如 "www.currentdomain.com"
  var currentHostname = window.location.hostname

  function getOtherHostnameNumber() {
    var currentHostname = window.location.hostname;
    var externalLinks = [];
    var totalLinks = 0;

    // 选择所有带有 href 的 a 标签
    $('a[href]').each(function () {
      var href = $(this).attr('href');
      totalLinks++;

      var url;
      try {
        url = new URL(href, window.location.origin);
      }
      catch (e) {
        // 不是合法 URL(如 javascript:、mailto:、#),跳过
        return;
      }

      var protocol = url.protocol;
      var hostname = url.hostname;

      // 只处理 HTTP 和 HTTPS 链接
      if (!protocol.startsWith('http')) {
        return;
      }

      // 判断是否是外部链接(域名不同)
      if (hostname !== currentHostname) {
        externalLinks.push({
          href: href,
          hostname: hostname
        });
      }
    });

    var externalCount = externalLinks.length;
    var internalCount = totalLinks - externalCount;

    console.log('总链接数:', totalLinks);
    console.log('外部链接数:', externalCount);
    console.log('内部链接数:', internalCount);
    console.log('外部链接详情:', externalLinks);

    // 判断页面类型(可根据需求调整阈值)
    var pageType = '普通页面'; // 默认
    var threshold = 150; // 🎯 你可以调整这个值,比如 8、10、12

    if (externalCount >= threshold) {
      pageType = '导航类页面(含有较多外部链接,可能是导航/目录/友情链接页)';
    }
    else if (externalCount > 0) {
      pageType = '普通页面(含有少量外部链接)';
      removeLinkAds()
    }
    else {
      pageType = '普通页面(未发现外部链接)';
      removeLinkAds()
    }
    return externalCount
  }

  // 获取所有带有 href 的 a 标签
  function removeLinkAds() {
    $('[aria-modal="true"][role="dialog"]').each(function (index) {
      $(this).remove()
    })

    $('a[href]').each(function () {
      var href = $(this).attr('href')

      var url
      try {
        // 尝试解析为完整 URL(支持相对路径)
        url = new URL(href, window.location.origin)
      }
      catch (e) {
        // 如果不是合法 URL(比如 javascript:, mailto:, #anchor),跳过不处理
        return
      }

      var linkProtocol = url.protocol
      var linkHostname = url.hostname

      // 只处理 http 和 https 协议的链接,其他如 mailto, tel, javascript 不处理
      if (!linkProtocol.startsWith('http')) {
        return
      }

      // 判断是否与当前域名相同
      if (linkHostname !== currentHostname) {
        console.log('发现外部链接,即将移除:', href, '域名:', linkHostname)

        // 移除该 <a> 元素
        $(this).remove()
      }
      else {
        // 同域链接,不做任何操作(也可标记,如添加 class)
        // $(this).addClass('internal-link');
      }
    })
  }

  // 主函数
  function removeAds() {
    // 1. 移除类名以"ad"开头的元素
    document.querySelectorAll('[class^="ad"], [id^="ad"]').forEach(function (el) {
      el.remove()
    })

    // 2. 移除常见广告容器
    const adSelectors = [
      'iframe[src*="ads"]',
      'div[class*="ad-"]',
      'div[class*="dialog"]',
      'div[id*="ad-"]'
    ]

    adSelectors.forEach(function (selector) {
      document.querySelectorAll(selector).forEach(function (el) {
        el.remove()
      })
    })

    // 3. 移除浮动广告(通常有固定定位)
    const floatingAds = document.querySelectorAll('div[style*="position:fixed"], div[style*="position:absolute"]')
    floatingAds.forEach(function (ad) {
      const rect = ad.getBoundingClientRect()
      // 如果广告靠近屏幕边缘(可能是浮动广告)
      if (rect.top < 10 || rect.bottom > window.innerHeight - 10 ||
        rect.left < 10 || rect.right > window.innerWidth - 10) {
        ad.remove()
      }
    })
  }

  // 移除base64广告图片
  function removeBase64Ads() {
    // 查找所有图片元素
    document.querySelectorAll('img').forEach(function (img) {
      try {
        // 检查src是否为base64编码
        const src = img.src
        if (src && src.startsWith('data:image')) {
          // 简单判断:如果图片很小且没有alt属性,可能是广告
          if (img.width < 200 && img.height < 200 && !img.alt) {
            img.remove()
          }
          // 或者检查src中是否包含常见广告关键词
          else if (src.includes('ad.') || src.includes('ads.') ||
            src.includes('doubleclick') || src.includes('adnxs') ||
            src.includes('track.')) {
            img.remove()
          }
        }
      }
      catch (e) {
        console.log('检查图片时出错:', e)
      }
    })
  }

  // 初始执行并设置定时检查
  function init() {
    removeAds()
    removeBase64Ads()
    getOtherHostnameNumber()

    // 监听DOM变化(适用于动态加载的内容)
    const observer = new MutationObserver(function () {
      removeAds()
      removeBase64Ads()
      getOtherHostnameNumber()
    })

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

  // 等待DOM加载完成
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init)
  }
  else {
    init()
  }
})();