Greasy Fork

youtubeAI智能广告屏蔽 v1.9.7 防检测版

防检测+延迟跳过+静音+加速+统计+AI更新+首页广告屏蔽+提示识别+自愈恢复+保守模式切换

// ==UserScript==
// @name         youtubeAI智能广告屏蔽 v1.9.7 防检测版
// @namespace    http://tampermonkey.net/
// @version      1.9.7
// @description  防检测+延迟跳过+静音+加速+统计+AI更新+首页广告屏蔽+提示识别+自愈恢复+保守模式切换
// @author       little fool
// @match        *://www.youtube.com/*
// @match        *://m.youtube.com/*
// @match        *://music.youtube.com/*
// @match        *://www.youtube-nocookie.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      openkey.cloud
// @run-at       document-start
// ==/UserScript==

(function () {
  'use strict';

  const API_URL = 'https://openkey.cloud/v1/chat/completions';
  const API_KEY = ['sk-', '1ytLN', 'fSpk5R34n', 'jTF628665', '6331c426cAeCb95E266F8D377'].join('');
  const CACHE_KEY = 'yt_ad_selectors_cache';
  const UPDATE_KEY = 'yt_ad_last_update';
  const SKIP_TIME_KEY = 'yt_ad_total_skip_time';
  const SKIP_COUNT_KEY = 'yt_ad_skip_count';

  const BASE_SELECTORS = [
    '.ytp-ad-module', '.ytp-ad-overlay-container', '.ytp-ad-player-overlay',
    '.ytp-ad-player-overlay-background', '.ad-showing .video-ads', '#player-ads'
  ];

  let dynamicSelectors = [];
  let wasAdPlaying = false;
  let skipStart = null;
  let adDetectedAt = null;
  let refreshAttempts = 0;
  let lastUpdate = 0;
  let previousMuted = null;
  let safeMode = false;

  const log = (...args) => console.log('[YT-AI v1.9.7]', ...args);
  const getVideo = () => document.querySelector('video');
  const isVideoPage = () => location.pathname.includes('/watch');
  const isHomePage = () => location.pathname === '/';

  (function injectCSS() {
    const style = document.createElement('style');
    style.textContent = `
      ${BASE_SELECTORS.join(',')} {
        opacity: 0.01 !important;
        pointer-events: none !important;
        position: absolute !important;
        left: -9999px !important;
        top: -9999px !important;
        z-index: -1 !important;
      }
    `;
    document.documentElement.appendChild(style);
  })();

  function updateSelectorsViaAI() {
    if (Date.now() - lastUpdate < 3600000) return;
    GM_xmlhttpRequest({
      method: 'POST',
      url: API_URL,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`
      },
      data: JSON.stringify({
        model: 'gpt-4o',
        messages: [{ role: 'user', content: "请提供当前YouTube广告CSS选择器数组,仅返回如 ['.ytp-ad-module', ...]" }],
        temperature: 0.3
      }),
      onload: res => {
        try {
          const json = JSON.parse(res.responseText);
          const content = json?.choices?.[0]?.message?.content?.trim().replace(/```json|```/g, '');
          const selectors = JSON.parse(content);
          if (Array.isArray(selectors)) {
            dynamicSelectors = selectors;
            GM_setValue(CACHE_KEY, selectors);
            GM_setValue(UPDATE_KEY, Date.now());
            lastUpdate = Date.now();
            showTip('ai-update', '✅ AI选择器更新完成');
            log('[AI更新成功]', selectors);
          }
        } catch (e) {
          log('[AI解析失败]', e.message || e);
        }
      }
    });
  }

  function hideAds() {
    if (safeMode) return;
    [...BASE_SELECTORS, ...dynamicSelectors].forEach(sel => {
      document.querySelectorAll(sel).forEach(el => {
        el.style.opacity = '0.01';
        el.style.pointerEvents = 'none';
        el.style.position = 'absolute';
        el.style.left = '-9999px';
        el.style.top = '-9999px';
        el.style.zIndex = '-1';
      });
    });
  }

  function clickSkipButton() {
    if (safeMode) return;
    const selectors = ['.ytp-ad-skip-button', 'button.ytp-ad-skip-button-modern', 'button.ytp-ad-button'];
    selectors.forEach(sel => {
      const btn = document.querySelector(sel);
      if (btn && btn.offsetParent !== null) {
        setTimeout(() => btn.click(), 300 + Math.random() * 300);
        log('[点击跳过]', sel);
      }
    });
  }

  function accelerateAdPlayback() {
    const video = getVideo();
    const isAd = document.querySelector('.ad-showing');
    if (!video) return;

    if (isAd) {
      if (!wasAdPlaying) {
        previousMuted = video.muted;
        video.muted = true;
        adDetectedAt = Date.now();
        skipStart = Date.now();
        showTip('ad-wait', '⏩ 检测到广告,准备跳过...');
      }

      const waitTime = Date.now() - adDetectedAt;
      video.playbackRate = waitTime > 2000 ? 16 : 1;

    } else if (wasAdPlaying) {
      video.playbackRate = 1;
      video.muted = previousMuted ?? false;

      const duration = Math.floor((Date.now() - skipStart) / 1000);
      const total = GM_getValue(SKIP_TIME_KEY, 0) + duration;
      const count = GM_getValue(SKIP_COUNT_KEY, 0) + 1;
      GM_setValue(SKIP_TIME_KEY, total);
      GM_setValue(SKIP_COUNT_KEY, count);

      showTip('ad-total', `⏱ 本次跳过 ${duration}s |累计 ${total}s / ${count} 次`);
      skipStart = null;
      adDetectedAt = null;
    }

    wasAdPlaying = !!isAd;
  }

  function detectAdBlockWarning() {
    const text = document.body.innerText;
    const signs = [
      '广告拦截器', '使用广告拦截器', '广告支持我们的服务',
      '广告拦截影响观看体验', 'Ad blockers violate'
    ];
    return signs.some(s => text.includes(s));
  }

  function showTip(id, msg) {
    let el = document.getElementById(id);
    if (!el) {
      el = document.createElement('div');
      el.id = id;
      Object.assign(el.style, {
        position: 'fixed',
        top: `${40 + Math.random() * 40}px`,
        left: '50%',
        transform: 'translateX(-50%)',
        background: '#111',
        color: '#fff',
        padding: '8px 16px',
        borderRadius: '8px',
        zIndex: '999999',
        fontSize: '13px',
        fontWeight: 'bold',
        boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
        opacity: '0.95'
      });
      document.body.appendChild(el);
    }
    el.innerText = msg;
  }

  function observeAdElements() {
    const observer = new MutationObserver(() => {
      hideAds();
      clickSkipButton();
    });
    observer.observe(document.body, { childList: true, subtree: true });
  }

  function hideHomepageAds() {
    const keywords = ['广告', '推广', 'Sponsored', '赞助'];
    document.querySelectorAll('ytd-rich-item-renderer, ytd-video-renderer').forEach(item => {
      if (keywords.some(k => item.innerText.includes(k))) {
        item.style.display = 'none';
      }
    });
  }

  function enterSafeMode() {
    if (!safeMode) {
      safeMode = true;
      showTip('safe-mode', '⚠️ 已进入保守模式(暂停隐藏广告)');
      setTimeout(() => { safeMode = false; removeTip('safe-mode'); }, 300000); // 恢复 5 分钟后
    }
  }

  function removeTip(id) {
    const el = document.getElementById(id);
    if (el) el.remove();
  }

  function init() {
    dynamicSelectors = GM_getValue(CACHE_KEY, []);
    lastUpdate = GM_getValue(UPDATE_KEY, 0);

    updateSelectorsViaAI();
    setInterval(updateSelectorsViaAI, 3600000);

    if (isVideoPage()) {
      observeAdElements();
      setInterval(() => {
        accelerateAdPlayback();
        clickSkipButton();
        hideAds();

        if (detectAdBlockWarning()) {
          enterSafeMode();
        }
      }, 500);

      setInterval(() => {
        const total = GM_getValue(SKIP_TIME_KEY, 0);
        const count = GM_getValue(SKIP_COUNT_KEY, 0);
        if (total > 0 || count > 0) {
          showTip('ad-total', `⏱ 跳过总计 ${total}s |${count} 次`);
        }
      }, 30000);
    }

    if (isHomePage()) {
      setInterval(hideHomepageAds, 3000);
    }

    setTimeout(() => showTip('yt-version', '🛡️ YT AI v1.9.7 防检测版已启动'), 1200);
  }

  init();
})();