// ==UserScript== // @name YouTube AI广告跳过增强 v2.0 // @namespace http://tampermonkey.net/ // @version 2.0 // @description 纯本地:自动识别广告、60倍速暴力跳过、静音、AI选择器更新、累计时长统计、无UI、无服务器、无上传。 // @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-end // @downloadURL https://update.greasyfork.icu/scripts/541052/YouTube%20AI%E5%B9%BF%E5%91%8A%E8%B7%B3%E8%BF%87%E5%A2%9E%E5%BC%BA%20v20.user.js // @updateURL https://update.greasyfork.icu/scripts/541052/YouTube%20AI%E5%B9%BF%E5%91%8A%E8%B7%B3%E8%BF%87%E5%A2%9E%E5%BC%BA%20v20.meta.js // ==/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 BASE_SELECTORS = [ '.ytp-ad-module', '.ytp-ad-overlay-container', '.ytp-ad-player-overlay', '.ad-showing .video-ads', '#player-ads' ]; let dynamicSelectors = []; let lastUpdate = 0; let wasAdPlaying = false; let previousMuted = null; let skipStart = null; let refreshAttempts = 0; const MAX_REFRESH_ATTEMPTS = 5; const REFRESH_INTERVAL = 5000; const getVideo = () => document.querySelector('video'); const isVideoPage = () => location.pathname.startsWith('/watch') || location.pathname.startsWith('/tv') || location.pathname.startsWith('/embed'); 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选择器数组,JSON格式,仅返回如 ['.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(); console.log('[AI选择器更新]', selectors); } } catch (e) { console.log('[AI更新失败]', e.message); } }, onerror: () => console.log('[AI请求失败]') }); } function hideAds() { [...BASE_SELECTORS, ...dynamicSelectors].forEach(sel => { document.querySelectorAll(sel).forEach(el => { el.style.cssText = 'opacity:0.01;pointer-events:none;position:absolute;left:-9999px;top:-9999px;z-index:0'; }); }); } function clickSkipButton() { const btn = document.querySelector('.ytp-ad-skip-button, .ytp-ad-skip-button-modern, .ytp-ad-button'); if (btn && btn.offsetParent !== null) { setTimeout(() => btn.click(), 200 + Math.random() * 300); } } function accelerateAdPlayback() { const video = getVideo(); const isAd = document.querySelector('.ad-showing'); if (!video) return; if (isAd) { video.playbackRate = 60; if (!wasAdPlaying) { previousMuted = video.muted; video.muted = true; skipStart = Date.now(); console.log('[广告中] 强制60x加速'); } } else if (wasAdPlaying) { video.playbackRate = 1; if (previousMuted !== null) video.muted = previousMuted; previousMuted = null; const duration = Math.floor((Date.now() - skipStart) / 1000); const total = GM_getValue(SKIP_TIME_KEY, 0) + duration; GM_setValue(SKIP_TIME_KEY, total); console.log(`[广告结束] 本次 ${duration}s |累计 ${total}s`); skipStart = null; } wasAdPlaying = !!isAd; } function detectAdBlockWarning() { const signs = [ '您似乎在使用广告拦截器', '广告支持我们的服务', '关闭广告拦截', 'Ad blockers violate YouTube’s Terms' ]; return signs.some(k => document.body.innerText.includes(k)); } function observeAdElements() { const observer = new MutationObserver(() => { hideAds(); clickSkipButton(); }); observer.observe(document.body, { childList: true, subtree: true }); } function init() { dynamicSelectors = GM_getValue(CACHE_KEY, []); lastUpdate = GM_getValue(UPDATE_KEY, 0); updateSelectorsViaAI(); setInterval(updateSelectorsViaAI, 3600000); if (isVideoPage()) { observeAdElements(); // ✅ 初始化时立即执行一次核心逻辑,避免延迟 hideAds(); clickSkipButton(); accelerateAdPlayback(); // 定时处理广告跳过与加速 setInterval(() => { accelerateAdPlayback(); clickSkipButton(); }, 500); // 侦测广告拦截器警告并自动刷新(最多5次) setInterval(() => { if (detectAdBlockWarning()) { if (refreshAttempts < MAX_REFRESH_ATTEMPTS) { refreshAttempts++; location.reload(); } } }, REFRESH_INTERVAL); } } init(); })();