Prioritize "Soft Skip" (Mute+Seek/Button), fallback to "Reload" with cooldown; uses MutationObserver; reduces detection risk. / 优先“软跳过”(按钮/静音+跳尾),失败时执行带冷却的“重载”;使用 MutationObserver + 兜底定时器;降低被风控概率。
目前為
// ==UserScript==
// @name YouTube Ad Auto-Skipper (VoidMuser)
// @version 2025.11.23.1
// @match https://www.youtube.com/*
// @match https://m.youtube.com/*
// @match https://music.youtube.com/*
// @exclude https://studio.youtube.com/*
// @grant none
// @license MIT
// @noframes
// @run-at document-idle
// @namespace
// @namespace
// @description Prioritize "Soft Skip" (Mute+Seek/Button), fallback to "Reload" with cooldown; uses MutationObserver; reduces detection risk. / 优先“软跳过”(按钮/静音+跳尾),失败时执行带冷却的“重载”;使用 MutationObserver + 兜底定时器;降低被风控概率。
// ==/UserScript==
(function () {
'use strict';
const DEBUG = false;
// 轮询节流
const CHECK_DEBOUNCE_MS = 100;
const INTERVAL_CHECK_MS = 800;
const SEEK_EPSILON = 0.1;
const state = {
checkTimer: null
};
const log = (...args) => { if (DEBUG) console.log('[ASYA]', ...args); };
const isMobile = location.hostname === 'm.youtube.com';
const isMusic = location.hostname === 'music.youtube.com';
// 只隐藏明确的广告相关容器,避免动到全局弹窗/菜单的宿主
function addCss() {
const style = document.createElement('style');
style.textContent = `
/* 广告容器:做透明处理,但不乱改 z-index,避免影响布局堆叠 */
#player-ads,
#panels > ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"],
.ytp-featured-product,
.ytp-ad-overlay-container,
.ytp-ad-text-overlay,
.ytp-ad-image-overlay,
.ytp-paid-content-overlay,
.yt-mealbar-promo-renderer,
ytd-merch-shelf-renderer,
ytmusic-mealbar-promo-renderer,
ytmusic-statement-banner-renderer {
opacity: 0 !important;
}
/* 叠在视频上面的广告层,禁用指针事件,防止挡住点击 */
.ytp-ad-overlay-container,
.ytp-ad-text-overlay,
.ytp-ad-image-overlay,
.ytp-paid-content-overlay {
pointer-events: none !important;
}
`;
(document.head || document.documentElement).appendChild(style);
}
function querySkipButton() {
const byClass = document.querySelector(
'.ytp-ad-skip-button, ' +
'.ytp-ad-skip-button-modern, ' +
'.ytp-ad-skip-button-slot, ' +
'.ytp-ad-skip-button-container button'
);
if (byClass) return byClass;
const btn = [...document.querySelectorAll('button')].find(b => {
const t = (b.getAttribute('aria-label') || b.textContent || '').trim();
return /skip ad|skip ads|跳过|跳過|繼續|Skip/i.test(t);
});
return btn || null;
}
function detectAdContext() {
const adShowing = !!document.querySelector('.ad-showing');
const pieCountdown = !!document.querySelector('.ytp-ad-timed-pie-countdown-container');
const survey = !!document.querySelector('.ytp-ad-survey-questions');
const skipBtn = querySkipButton();
const adLikely = adShowing || pieCountdown || survey || !!skipBtn;
return { adShowing, pieCountdown, survey, skipBtn, adLikely };
}
function getPlayers() {
const moviePlayerEl = document.querySelector('#movie_player') || null;
let playerEl = null;
let player = null;
if (isMobile || isMusic) {
playerEl = moviePlayerEl;
player = moviePlayerEl;
} else {
const ytd = document.querySelector('#ytd-player');
playerEl = ytd || moviePlayerEl || null;
if (ytd && typeof ytd.getPlayer === 'function') {
try { player = ytd.getPlayer(); } catch (_) {}
}
if (!player && moviePlayerEl) player = moviePlayerEl;
}
return { moviePlayerEl, playerEl, player };
}
function trySoftSkip(players, ctx) {
// 1. 如有跳过按钮,模拟人类点击
if (ctx.skipBtn) {
const delay = 300 + Math.random() * 500; // 300~800ms
setTimeout(() => {
try {
if (ctx.skipBtn && ctx.skipBtn.click) {
ctx.skipBtn.click();
log('Human-like clicked skip button after', delay, 'ms');
// 点击后稍微再检查一次,处理连播广告
setTimeout(() => {
scheduleCheck(0);
}, 50);
}
} catch (e) {
log('Click failed', e);
}
}, delay);
return true;
}
// 2. 无按钮时:静音 + 16x + 跳至尾部(仅在判断为广告时执行)
if (ctx.adLikely) {
const adVideo = document.querySelector('video.html5-main-video');
if (adVideo && !Number.isNaN(adVideo.duration) && adVideo.duration > 0) {
try {
const targetTime = Math.max(0, adVideo.duration - SEEK_EPSILON);
if (adVideo.currentTime < targetTime) {
adVideo.muted = true;
adVideo.playbackRate = 16;
adVideo.currentTime = targetTime;
log('Muted + 16x + seek to end');
return true;
}
} catch (_) {}
}
}
return false;
}
function skipAd() {
const ctx = detectAdContext();
if (ctx.adLikely) {
log('Ad detected. Context:', ctx);
const players = getPlayers();
const handled = trySoftSkip(players, ctx);
if (handled) {
// 处理过后,再过一段时间确认是否还有下一段广告
scheduleCheck(1000);
}
}
}
// 调度器:防抖
function scheduleCheck(delayMs = CHECK_DEBOUNCE_MS) {
if (state.checkTimer) clearTimeout(state.checkTimer);
state.checkTimer = setTimeout(() => {
skipAd();
state.checkTimer = null;
}, delayMs);
}
// 观察广告状态变化
function setupObserver() {
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
const el = m.target;
if (
el &&
el.classList &&
(el.classList.contains('ad-showing') ||
el.classList.contains('ytp-ad-skip-button-container'))
) {
scheduleCheck(0);
return;
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class', 'style']
});
}
// === 入口 ===
addCss();
setupObserver();
scheduleCheck(0);
// 心跳轮询,兜底
setInterval(() => scheduleCheck(), INTERVAL_CHECK_MS);
log('Script loaded (Fixed Version)');
})();