// ==UserScript==
// @name xyDouYinTools 抖音沉浸式优化
// @namespace https://greasyfork.org/zh-CN/users/1513167-%E9%83%A7%E5%B1%B1%E6%9D%8E%E5%92%B8%E9%B1%BC
// @version 0.28.1
// @description 美化抖音界面 一个偏沉浸式观感(最大程度全屏化) + 纯鼠标刷视频的抖音网页端增强脚本:尽量让视频当主角,UI少打扰;同时把高频操作塞到鼠标手势里,省得手来回摸键盘。
// @author lxy
// @license MIT
// @match https://www.douyin.com/*
// @match https://live.douyin.com/*
// @match https://www.douyin.com/follow/live/*
// @run-at document-start
// @grant none
// @downloadURL https://update.greasyfork.icu/scripts/548904/xyDouYinTools%20%E6%8A%96%E9%9F%B3%E6%B2%89%E6%B5%B8%E5%BC%8F%E4%BC%98%E5%8C%96.user.js
// @updateURL https://update.greasyfork.icu/scripts/548904/xyDouYinTools%20%E6%8A%96%E9%9F%B3%E6%B2%89%E6%B5%B8%E5%BC%8F%E4%BC%98%E5%8C%96.meta.js
// ==/UserScript==
(function() {
'use strict';
const FEATURE = {
SIDEBAR: 1,
STYLES: 1,
NAVIGATION: 1,
LIVE: 1,
HIDE_ELEMENTS: 1,
ADS: 1,
MOUSE: 1,
LOADING: 1,
PERFORMANCE: 1
};
const DEBUG = {
LOG_LEVEL: 3,
MODULES: {
SIDEBAR: 0,
STYLES: 0,
NAVIGATION: 1,
LIVE: 0,
HIDE_ELEMENTS: 1,
ADS: 1,
MOUSE: 0,
LOADING: 0,
PERFORMANCE: 1
}
};
const LS_PREFIX = 'xyDYTools_feature_';
(function loadFeatureFlags() {
try {
Object.keys(FEATURE).forEach(k => {
const v = localStorage.getItem(LS_PREFIX + k);
if (v === '0') FEATURE[k] = 0;
if (v === '1') FEATURE[k] = 1;
});
} catch (_) {}
})();
const nativeConsole = {
log: console.log.bind(console),
warn: console.warn.bind(console),
error: console.error.bind(console),
info: console.info.bind(console),
time: console.time ? console.time.bind(console) : null,
timeEnd: console.timeEnd ? console.timeEnd.bind(console) : null
};
if (DEBUG.LOG_LEVEL === 0) {
['log', 'warn', 'error', 'info'].forEach(type => {
console[type] = function() {};
});
}
function ts() {
return new Date().toLocaleTimeString();
}
const logger = {
log(module, message, ...args) {
if (DEBUG.LOG_LEVEL >= 3 && DEBUG.MODULES[module]) nativeConsole.log(
`[${ts()}] [DouYinTools] [${module}]`, message, ...args);
},
warn(module, message, ...args) {
if (DEBUG.LOG_LEVEL >= 2 && DEBUG.MODULES[module]) nativeConsole.warn(
`[${ts()}] [DouYinTools] [${module}]`, message, ...args);
},
error(module, message, ...args) {
if (DEBUG.LOG_LEVEL >= 1 && DEBUG.MODULES[module]) nativeConsole.error(
`[${ts()}] [DouYinTools] [${module}]`, message, ...args);
},
info(module, message, ...args) {
if (DEBUG.LOG_LEVEL >= 3 && DEBUG.MODULES[module]) nativeConsole.info(
`[${ts()}] [DouYinTools] [${module}]`, message, ...args);
},
initModule(module) {
if (DEBUG.LOG_LEVEL >= 3 && DEBUG.MODULES[module]) nativeConsole.log(
`[${ts()}] [DouYinTools] [${module}] 模块初始化开始`);
},
moduleReady(module) {
if (DEBUG.LOG_LEVEL >= 3 && DEBUG.MODULES[module]) nativeConsole.log(
`[${ts()}] [DouYinTools] [${module}] 模块初始化完成`);
}
};
const performanceTracker = {
startTime: performance.now(),
moduleTimes: {},
moduleStartTimes: {},
start(module) {
if (FEATURE.PERFORMANCE && DEBUG.MODULES.PERFORMANCE && DEBUG.LOG_LEVEL >= 3) {
this.moduleStartTimes[module] = performance.now();
logger.log('PERFORMANCE', `开始执行: ${module}`);
}
},
end(module) {
if (!(FEATURE.PERFORMANCE && DEBUG.MODULES.PERFORMANCE && DEBUG.LOG_LEVEL >= 3)) return 0;
if (!this.moduleStartTimes[module]) return 0;
const duration = performance.now() - this.moduleStartTimes[module];
this.moduleTimes[module] = duration;
logger.log('PERFORMANCE', `${module} 执行完成, 耗时: ${duration.toFixed(2)}ms`);
delete this.moduleStartTimes[module];
return duration;
},
getTotalTime() {
return (performance.now() - this.startTime).toFixed(2);
},
printPerformanceReport() {
if (!(FEATURE.PERFORMANCE && DEBUG.MODULES.PERFORMANCE && DEBUG.LOG_LEVEL >= 3)) return;
const totalTime = this.getTotalTime();
const entries = Object.entries(this.moduleTimes).sort((a, b) => b[1] - a[1]);
const sum = entries.reduce((acc, [, t]) => acc + t, 0);
nativeConsole.log('\n' + '='.repeat(60));
nativeConsole.log('%c🎯 抖音工具脚本性能报告', 'color: #4CAF50; font-size: 16px; font-weight: bold;');
nativeConsole.log('='.repeat(60));
nativeConsole.log('%c📊 模块执行时间统计:', 'color: #2196F3; font-weight: bold;');
entries.forEach(([module, time]) => {
const percent = sum > 0 ? ((time / sum) * 100).toFixed(1) : '0.0';
nativeConsole.log(` ${module}: ${time.toFixed(2)}ms (${percent}%)`);
});
nativeConsole.log('%c⏱️ 总运行时间统计:', 'color: #FF9800; font-weight: bold;');
nativeConsole.log(` 脚本总运行时间: ${totalTime}ms`);
nativeConsole.log(` 模块总耗时: ${sum.toFixed(2)}ms`);
nativeConsole.log('%c⚙️ 调试配置:', 'color: #9C27B0; font-weight: bold;');
nativeConsole.log(` 日志级别: ${DEBUG.LOG_LEVEL}`);
nativeConsole.log(
` 输出模块: ${Object.keys(DEBUG.MODULES).filter(m => DEBUG.MODULES[m]).length}/${Object.keys(DEBUG.MODULES).length}`
);
nativeConsole.log('%c🧩 功能开关:', 'color: #795548; font-weight: bold;');
Object.keys(FEATURE).forEach(k => nativeConsole.log(` ${k}: ${FEATURE[k] ? '✅ 开启' : '❌ 关闭'}`));
nativeConsole.log('='.repeat(60) + '\n');
return totalTime;
}
};
function sleep(ms) {
return new Promise(r => setTimeout(r, ms));
}
function normText(s) {
return String(s || '').replace(/\s+/g, ' ').trim();
}
function isVisible(el) {
if (!el) return false;
const st = getComputedStyle(el);
if (st.display === 'none' || st.visibility === 'hidden' || Number(st.opacity) === 0) return false;
const r = el.getBoundingClientRect();
if (r.width < 5 || r.height < 5) return false;
return r.bottom > 0 && r.top < window.innerHeight && r.right > 0 && r.left < window.innerWidth;
}
function dispatchKeyEvent(type, key, repeat) {
const code = key.length === 1 ? `Key${key.toUpperCase()}` : key;
const k = key.length === 1 ? key : (key === 'ArrowDown' ? 'ArrowDown' : key);
const keyCode = key.length === 1 ? key.charCodeAt(0) : (key === 'ArrowDown' ? 40 : 0);
const ev = new KeyboardEvent(type, {
key: k,
code,
keyCode,
which: keyCode,
bubbles: true,
cancelable: true,
repeat: !!repeat
});
document.dispatchEvent(ev);
}
function keyDown(key, repeat) {
dispatchKeyEvent('keydown', key, repeat);
}
function keyUp(key) {
dispatchKeyEvent('keyup', key, false);
}
function createLoadingScreen() {
performanceTracker.start('LOADING_SCREEN');
logger.initModule('LOADING');
if (!FEATURE.LOADING) {
logger.moduleReady('LOADING');
performanceTracker.end('LOADING_SCREEN');
return;
}
const EXIST_ID = 'tm-fullscreen-loader';
if (document.getElementById(EXIST_ID)) {
logger.moduleReady('LOADING');
performanceTracker.end('LOADING_SCREEN');
return;
}
const FADE_MS = 450;
const MIN_SHOW_MS = 250;
const MAX_SHOW_MS = 12000;
const ESC_TO_CLOSE = true;
const CLICK_TO_CLOSE = true;
window.__xyDYToolsBoot = window.__xyDYToolsBoot || {
styles: false,
safeStyles: false,
nav: false,
ads: false,
hide: false,
inited: false
};
if (!document.getElementById('tm-fullscreen-loader-style')) {
const style = document.createElement('style');
style.id = 'tm-fullscreen-loader-style';
style.textContent =
`#tm-fullscreen-loader{position:fixed;inset:0;background:rgba(0,0,0,0.92);z-index:999999;display:flex;justify-content:center;align-items:center;flex-direction:column;opacity:1;transition:opacity ${FADE_MS}ms ease;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);}#tm-fullscreen-loader .tm-spinner{width:52px;height:52px;border:5px solid rgba(255,255,255,0.26);border-radius:50%;border-top-color:#fff;animation:tm_spin 0.95s linear infinite;}#tm-fullscreen-loader .tm-loading-text{color:#fff;margin-top:18px;font-family:Arial,sans-serif;}#tm-fullscreen-loader .s1{font-size:18px;font-weight:600;letter-spacing:0.5px;}#tm-fullscreen-loader .s2{color:rgba(255,255,255,0.62);font-size:13px;margin-top:10px;max-width:min(560px, 86vw);text-align:center;line-height:1.45;}#tm-fullscreen-loader .hint{color:rgba(255,255,255,0.45);font-size:12px;margin-top:14px;text-align:center;}@keyframes tm_spin{to{transform:rotate(360deg);}}`;
(document.head || document.documentElement).appendChild(style);
}
const loader = document.createElement('div');
loader.id = EXIST_ID;
loader.innerHTML = `
加载中...
正在等抖音自身加载 + 脚本正在接管抖音界面
${ESC_TO_CLOSE ? '按 ESC 可关闭 / ' : ''}${CLICK_TO_CLOSE ? '点一下也能关' : ''}
UI正在挨打,场面会略显混乱
`;
document.documentElement.appendChild(loader);
let removed = false;
const startAt = Date.now();
const remove = (reason) => {
if (removed) return;
removed = true;
const cost = Date.now() - startAt;
logger.log('LOADING', `加载界面移除:${reason},展示 ${cost}ms`);
loader.style.opacity = '0';
setTimeout(() => {
try {
loader.remove();
} catch (_) {}
try {
document.getElementById('tm-fullscreen-loader-style')?.remove();
} catch (_) {}
}, FADE_MS + 30);
};
const safeRemove = (reason) => {
const elapsed = Date.now() - startAt;
const wait = Math.max(0, MIN_SHOW_MS - elapsed);
setTimeout(() => remove(reason), wait);
};
function isBootReady() {
const b = window.__xyDYToolsBoot || {};
return !!b.inited;
}
function isDomReady() {
return document.readyState === 'interactive' || document.readyState === 'complete';
}
const POLL_MS = 120;
const AFTER_READY_MS = 1200;
(function poll() {
if (removed) return;
if (isDomReady() && isBootReady()) {
setTimeout(() => {
requestAnimationFrame(() => requestAnimationFrame(() => safeRemove('BOOT_READY')));
}, AFTER_READY_MS);
return;
}
setTimeout(poll, POLL_MS);
})();
setTimeout(() => safeRemove('MAX_SHOW_TIMEOUT'), MAX_SHOW_MS);
if (ESC_TO_CLOSE) {
window.addEventListener('keydown', function onKey(e) {
if (e.key === 'Escape') {
window.removeEventListener('keydown', onKey, true);
safeRemove('ESC');
}
}, true);
}
if (CLICK_TO_CLOSE) loader.addEventListener('click', () => safeRemove('CLICK'), {
once: true
});
logger.moduleReady('LOADING');
performanceTracker.end('LOADING_SCREEN');
}
/* =========================
SIDEBAR(修复版)
你这个“抽风”核心点基本就俩:
1) mousemove 里只看 x<=hoverWidth,会把“鼠标已经在侧栏里”的情况当成“离开左侧边缘”,从而立刻排队隐藏
2) MutationObserver 盯整个 documentElement subtree,抖音一更新 DOM 你就疯狂重绑监听,状态来回抖
下面这版:用 RAF 限频 + 用“鼠标是否在侧栏矩形内”来决定显隐 + 只在侧栏节点变更时重绑
========================= */
const SIDEBAR_CONFIG = {
hoverDelay: 240,
hoverWidth: 18,
storageKey: 'hide_sidebar',
lockKey: 'hide_sidebar_lock',
repairKey: 'xyDYTools_sidebar_repair_v1'
};
let sidebarHoverEnabled = false;
let sidebarHideTimer = null;
let sidebarVisible = false;
let sidebarElCache = null;
let sidebarBindToken = 0;
let rafMovePending = false;
let lastMoveX = 0;
let lastMoveY = 0;
function safeLSGet(key) {
try {
return localStorage.getItem(key);
} catch (_) {
return null;
}
}
function safeLSSet(key, val) {
try {
localStorage.setItem(key, val);
} catch (_) {}
}
function safeLSDel(key) {
try {
localStorage.removeItem(key);
} catch (_) {}
}
function pickSidebarEl() {
return (
document.querySelector('#douyin-navigation') ||
document.querySelector('[data-e2e="douyin-navigation"]') ||
null
);
}
function isSidebarLocked() {
return safeLSGet(SIDEBAR_CONFIG.lockKey) === 'true';
}
function isHideSidebarWanted() {
return safeLSGet(SIDEBAR_CONFIG.storageKey) === 'true';
}
function setSidebarHiddenOnRoot(hidden) {
if (hidden) {
document.documentElement.classList.add('xy-hide-sidebar');
sidebarVisible = false;
} else {
document.documentElement.classList.remove('xy-hide-sidebar');
sidebarVisible = true;
}
}
(function injectSidebarStyle() {
if (document.getElementById('xy-sidebar-style')) return;
const style = document.createElement('style');
style.id = 'xy-sidebar-style';
style.textContent = `
html.xy-hide-sidebar #douyin-navigation{display:none !important;}
html.xy-hide-sidebar [data-e2e="douyin-navigation"]{display:none !important;}
html.xy-hide-sidebar #douyin-navigation,
html.xy-hide-sidebar [data-e2e="douyin-navigation"]{
transition:none !important;
}
html.xy-hide-sidebar #douyin-navigation *,
html.xy-hide-sidebar [data-e2e="douyin-navigation"] *{
pointer-events:none !important;
}
html:not(.xy-hide-sidebar) #douyin-navigation{display:block !important;}
html:not(.xy-hide-sidebar) [data-e2e="douyin-navigation"]{display:block !important;}
`;
(document.head || document.documentElement).appendChild(style);
})();
(function sidebarLSRepairOnce() {
const mark = safeLSGet(SIDEBAR_CONFIG.repairKey);
if (mark === '1') return;
const a = safeLSGet(SIDEBAR_CONFIG.storageKey);
const b = safeLSGet(SIDEBAR_CONFIG.lockKey);
if (a !== null && a !== 'true' && a !== 'false') safeLSDel(SIDEBAR_CONFIG.storageKey);
if (b !== null && b !== 'true' && b !== 'false') safeLSDel(SIDEBAR_CONFIG.lockKey);
if (safeLSGet(SIDEBAR_CONFIG.lockKey) === 'true') safeLSSet(SIDEBAR_CONFIG.storageKey, 'true');
safeLSSet(SIDEBAR_CONFIG.repairKey, '1');
})();
function clearSidebarTimers() {
if (sidebarHideTimer) {
clearTimeout(sidebarHideTimer);
sidebarHideTimer = null;
}
}
function mouseInsideSidebarRect(x, y) {
const el = sidebarElCache || pickSidebarEl();
if (!el) return false;
const r = el.getBoundingClientRect();
if (r.width <= 0 || r.height <= 0) return false;
return x >= r.left && x <= r.right && y >= r.top && y <= r.bottom;
}
function shouldShowSidebarByMouse(x, y) {
if (!sidebarHoverEnabled) return false;
if (isSidebarLocked()) return false;
if (!isHideSidebarWanted()) return false;
if (x <= SIDEBAR_CONFIG.hoverWidth) return true;
if (mouseInsideSidebarRect(x, y)) return true;
return false;
}
function scheduleHideIfNeeded(x, y) {
if (!sidebarHoverEnabled) return;
if (isSidebarLocked()) return;
const wantHide = isHideSidebarWanted();
if (!wantHide) {
setSidebarHiddenOnRoot(false);
clearSidebarTimers();
return;
}
const shouldShow = shouldShowSidebarByMouse(x, y);
if (shouldShow) {
clearSidebarTimers();
if (!sidebarVisible) setSidebarHiddenOnRoot(false);
return;
}
if (!sidebarVisible) return;
clearSidebarTimers();
sidebarHideTimer = setTimeout(() => {
sidebarHideTimer = null;
if (!isHideSidebarWanted()) return;
const x2 = lastMoveX;
const y2 = lastMoveY;
if (shouldShowSidebarByMouse(x2, y2)) return;
setSidebarHiddenOnRoot(true);
}, SIDEBAR_CONFIG.hoverDelay);
}
function onPointerMove(e) {
if (!FEATURE.SIDEBAR) return;
if (!sidebarHoverEnabled) return;
if (isSidebarLocked()) return;
lastMoveX = e.clientX;
lastMoveY = e.clientY;
if (rafMovePending) return;
rafMovePending = true;
requestAnimationFrame(() => {
rafMovePending = false;
scheduleHideIfNeeded(lastMoveX, lastMoveY);
});
}
function bindSidebarHoverOnce() {
const token = ++sidebarBindToken;
document.removeEventListener('pointermove', onPointerMove, true);
document.addEventListener('pointermove', onPointerMove, {
passive: true,
capture: true
});
setTimeout(() => {
if (token !== sidebarBindToken) return;
sidebarElCache = pickSidebarEl();
}, 0);
}
function watchSidebarMount() {
let lastEl = null;
let debounce = null;
const ensure = () => {
const el = pickSidebarEl();
if (el && el !== lastEl) {
lastEl = el;
sidebarElCache = el;
bindSidebarHoverOnce();
scheduleHideIfNeeded(lastMoveX || 9999, lastMoveY || 9999);
}
};
const ob = new MutationObserver(() => {
if (!FEATURE.SIDEBAR) return;
if (debounce) return;
debounce = setTimeout(() => {
debounce = null;
ensure();
}, 180);
});
const root = document.body || document.documentElement;
if (root) ob.observe(root, {
childList: true,
subtree: true
});
setInterval(() => {
if (!FEATURE.SIDEBAR) return;
ensure();
}, 2500);
}
function setSidebarLock(locked) {
safeLSSet(SIDEBAR_CONFIG.lockKey, locked ? 'true' : 'false');
if (locked) {
safeLSSet(SIDEBAR_CONFIG.storageKey, 'true');
sidebarHoverEnabled = false;
clearSidebarTimers();
setSidebarHiddenOnRoot(true);
logger.log('SIDEBAR', '已锁定隐藏');
return;
}
sidebarHoverEnabled = true;
const wantHide = isHideSidebarWanted();
setSidebarHiddenOnRoot(!!wantHide);
bindSidebarHoverOnce();
logger.log('SIDEBAR', '已解锁');
}
function initSidebarState() {
performanceTracker.start('SIDEBAR_INIT');
logger.initModule('SIDEBAR');
if (!FEATURE.SIDEBAR) {
setSidebarHiddenOnRoot(false);
sidebarHoverEnabled = false;
clearSidebarTimers();
logger.moduleReady('SIDEBAR');
performanceTracker.end('SIDEBAR_INIT');
return;
}
if (isSidebarLocked()) {
safeLSSet(SIDEBAR_CONFIG.storageKey, 'true');
setSidebarHiddenOnRoot(true);
sidebarHoverEnabled = false;
clearSidebarTimers();
logger.moduleReady('SIDEBAR');
performanceTracker.end('SIDEBAR_INIT');
return;
}
sidebarHoverEnabled = true;
const wantHide = isHideSidebarWanted();
setSidebarHiddenOnRoot(!!wantHide);
bindSidebarHoverOnce();
watchSidebarMount();
logger.moduleReady('SIDEBAR');
performanceTracker.end('SIDEBAR_INIT');
}
function initSidebarToggle() {
performanceTracker.start('SIDEBAR_SETUP');
logger.initModule('SIDEBAR');
initSidebarState();
logger.moduleReady('SIDEBAR');
performanceTracker.end('SIDEBAR_SETUP');
}
window.xyDYTools = window.xyDYTools || {};
window.xyDYTools.sidebar = window.xyDYTools.sidebar || {};
window.xyDYTools.sidebar.clearLS = function() {
safeLSDel(SIDEBAR_CONFIG.storageKey);
safeLSDel(SIDEBAR_CONFIG.lockKey);
safeLSDel(SIDEBAR_CONFIG.repairKey);
return 'ok';
};
/* ========================= */
function injectStyles() {
performanceTracker.start('STYLES_INJECTION');
logger.initModule('STYLES');
if (!FEATURE.STYLES) {
logger.moduleReady('STYLES');
performanceTracker.end('STYLES_INJECTION');
return;
}
if (!document.head) {
setTimeout(injectStyles, 100);
return;
}
if (document.getElementById('douyin-dynamic-styles')) {
logger.moduleReady('STYLES');
performanceTracker.end('STYLES_INJECTION');
return;
}
const style = document.createElement('style');
style.id = 'douyin-dynamic-styles';
style.innerHTML = `
.wUFzLKZF.danmakuContainer,.xgplayer-immersive-switch-setting.immersive-switch{display:none !important;}
#douyin-header{
background:rgba(0,0,0,0.10) !important;
backdrop-filter:blur(5px) !important;
-webkit-backdrop-filter:blur(5px) !important;
position:fixed;
top:0;left:0;width:100%;
z-index:1000;
border-bottom:1px solid rgba(255,255,255,0.10) !important;
will-change:transform;
}
html.tm-nav-autohide #douyin-header{
transform:translateY(-100%);
transition:transform 0.28s ease;
}
html.tm-nav-autohide #douyin-header.show{transform:translateY(0);}
html:not(.tm-nav-autohide) #relatedVideoCard{padding-top:60px !important;}
#douyin-right-container{padding:0 !important;}
.ES4ZDMnf.N07M3gwz.isDark.nUy2mwhv.tC5Oyw9g{background:transparent !important;backdrop-filter:blur(5px) !important;-webkit-backdrop-filter:blur(5px) !important;}
.P2uoik9n .basePlayerContainer:not(.highlightPlayer) .xgplayer-controls{background-image:none !important;background:rgba(255,255,255,0.06) !important;backdrop-filter:blur(1px) saturate(1.1) !important;-webkit-backdrop-filter:blur(1px) saturate(1.1) !important;border:1px solid rgba(255,255,255,0.06) !important;box-shadow:none !important;transition:background 0.18s ease,backdrop-filter 0.18s ease,-webkit-backdrop-filter 0.18s ease,border-color 0.18s ease !important;}
.P2uoik9n .basePlayerContainer:not(.highlightPlayer) .xgplayer-controls:hover{background:rgba(255,255,255,0.16) !important;backdrop-filter:blur(16px) saturate(1.8) !important;-webkit-backdrop-filter:blur(16px) saturate(1.8) !important;border-color:rgba(255,255,255,0.10) !important;}
.xgplayer-controls.show{transform:translateY(0);}
#video-info-wrap{opacity:0.3 !important;transition:opacity 0.3s ease !important;}
#video-info-wrap:hover{opacity:1 !important;}
.video-info-mask,.UXyEyqbq.UdkDK3ea.DZKZZklc{display:none !important;}
.xg-video-container{height:100% !important;margin:auto 0 !important;bottom:0 !important;}
.L1TH4HdO.d6KxRih3.positionBox,.L1TH4HdO.positionBox{display:none !important;}
.nM3w4mVK.byAYwK4P.fullscreen_capture_feedback._z4WuFBP.NdwOHaIw{height:100% !important;border-radius:0 !important;}
.nM3w4mVK .kkbhJDRa{width:calc(100%) !important;height:calc(100%) !important;border-radius:0 !important;}
#sliderVideo,#sliderVideo::before,#sliderVideo::after{border-radius:0 !important;clip-path:none !important;-webkit-clip-path:none !important;mask:none !important;-webkit-mask:none !important;}
#slider-card{border-radius:0 !important;overflow:visible !important;}
.PsHhivd9.sHGvkSIn,.Q6VYnosf.userMenuPanelShadowAnimation,.yZlWL2BG,.vtP34xIV.sRPWIReI *,.vlXyJ9Hj,.h3JxiXCd.ZiQxU1tx *,.N3mRyy_g.popShadowAnimation,.F_XLoeLO.c64lf7w4,.ScTolygy.q1kuhAxH,.eBcBNgnP.PHb7B2cG,.k9soqkkm{
background:rgba(255,255,255,0.25) !important;
backdrop-filter:blur(10px) saturate(180%) !important;
-webkit-backdrop-filter:blur(10px) saturate(180%) !important;
border-radius:12px !important;
border:1px solid rgba(255,255,255,0.6) !important;
box-shadow:0 4px 12px rgba(0,0,0,0.05),inset 0 1px 0 rgba(255,255,255,0.6) !important;
color:rgba(0,0,0,0.85) !important;
}
.PsHhivd9.sHGvkSIn,.Q6VYnosf.userMenuPanelShadowAnimation,.yZlWL2BG *,.vlXyJ9Hj,.N3mRyy_g.popShadowAnimation *,.F_XLoeLO.c64lf7w4 *,.ScTolygy.q1kuhAxH *,.eBcBNgnP.PHb7B2cG *,.k9soqkkm *{
color:rgba(0,0,0,0.85) !important;
text-shadow:0 1px 1px rgba(255,255,255,0.35);
}
.semi-button.semi-button-primary.semi-button-size-small.B7L9kG57{
background:rgba(180,30,45,0.75) !important;
backdrop-filter:blur(8px) saturate(120%) !important;
-webkit-backdrop-filter:blur(8px) saturate(120%) !important;
color:rgba(255,255,255,0.95) !important;
border:1px solid rgba(255,255,255,0.25) !important;
border-radius:999px !important;
font-weight:600;
}
.semi-button.semi-button-primary.semi-button-size-small.B7L9kG57:hover{
background:rgba(255,77,79,0.9) !important;
transform:translateY(-1px);
box-shadow:0 4px 10px rgba(0,0,0,0.2) !important;
}
`;
document.head.appendChild(style);
logger.moduleReady('STYLES');
performanceTracker.end('STYLES_INJECTION');
}
function injectSafeStyles() {
performanceTracker.start('SAFE_STYLES');
logger.initModule('STYLES');
if (!FEATURE.STYLES) {
logger.moduleReady('STYLES');
performanceTracker.end('SAFE_STYLES');
return;
}
const styleId = 'douyin-safe-styles';
let style = document.getElementById(styleId);
if (!style) {
style = document.createElement('style');
style.id = styleId;
if (!document.head) {
setTimeout(injectSafeStyles, 100);
return;
}
document.head.appendChild(style);
}
style.textContent =
`.xgplayer-playswitch.recommend-out-switch-btn{visibility:hidden !important;opacity:0 !important;}.fullscreen_capture_feedback{padding-right:0 !important;}`;
logger.moduleReady('STYLES');
performanceTracker.end('SAFE_STYLES');
}
function initTopNavigation() {
performanceTracker.start('NAVIGATION_INIT');
logger.initModule('NAVIGATION');
if (!FEATURE.NAVIGATION) {
document.documentElement.classList.remove('tm-nav-autohide');
const h = document.getElementById('douyin-header');
if (h) h.classList.add('show');
logger.moduleReady('NAVIGATION');
performanceTracker.end('NAVIGATION_INIT');
return;
}
let header = null;
let lastMouseY = 9999;
let showTimeout = null;
let hideTimeout = null;
let inactivityTimer = null;
let bound = false;
function findHeader() {
header = document.getElementById('douyin-header');
return !!header;
}
function showHeader() {
if (!header) return;
clearTimeout(hideTimeout);
hideTimeout = null;
if (showTimeout) return;
showTimeout = setTimeout(() => {
if (!header) return;
header.classList.add('show');
showTimeout = null;
}, 0);
}
function hideHeader() {
if (!header) return;
clearTimeout(showTimeout);
showTimeout = null;
if (hideTimeout) return;
hideTimeout = setTimeout(() => {
if (!header) return;
header.classList.remove('show');
hideTimeout = null;
}, 160);
}
function resetInactivity() {
clearTimeout(inactivityTimer);
inactivityTimer = setTimeout(() => {
if (lastMouseY > 120) hideHeader();
}, 1200);
}
function onMouseMove(e) {
lastMouseY = e.clientY;
if (e.clientY <= 14) {
showHeader();
resetInactivity();
}
}
function onWindowOut(e) {
if (!e.relatedTarget && !e.toElement) hideHeader();
}
function bindOnce() {
if (bound) return;
bound = true;
document.addEventListener('mousemove', onMouseMove, true);
window.addEventListener('blur', hideHeader, true);
document.addEventListener('mouseout', onWindowOut, true);
window.addEventListener('scroll', () => {
if (lastMouseY > 120) hideHeader();
}, {
passive: true
});
}
function enable() {
document.documentElement.classList.add('tm-nav-autohide');
showHeader();
setTimeout(() => {
if (lastMouseY > 120) hideHeader();
}, 800);
}
function boot() {
if (!findHeader()) {
setTimeout(boot, 700);
return;
}
bindOnce();
enable();
logger.moduleReady('NAVIGATION');
performanceTracker.end('NAVIGATION_INIT');
}
boot();
(function watchRebuild() {
const ob = new MutationObserver(() => {
if (!FEATURE.NAVIGATION) return;
const h = document.getElementById('douyin-header');
if (h && h !== header) {
header = h;
showHeader();
setTimeout(() => {
if (lastMouseY > 120) hideHeader();
}, 600);
}
});
ob.observe(document.documentElement, {
childList: true,
subtree: true
});
})();
}
const LIVE_CONFIG = {
debounceDelay: 3000
};
let lastPressTime = 0;
let liveCheckInterval;
function isElementVisible(el) {
if (!el) return false;
const rect = el.getBoundingClientRect();
return (rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0 && rect.bottom <= window
.innerHeight && rect.right <= window.innerWidth);
}
function startLiveCheck() {
performanceTracker.start('LIVE_DETECTION');
logger.initModule('LIVE');
if (!FEATURE.LIVE) {
logger.moduleReady('LIVE');
performanceTracker.end('LIVE_DETECTION');
return;
}
if (liveCheckInterval) clearInterval(liveCheckInterval);
liveCheckInterval = setInterval(() => {
const liveIndicators = document.querySelectorAll(
'.live-indicator, [data-e2e="live-indicator"]');
const visibleLive = Array.from(liveIndicators).filter(isElementVisible);
if (visibleLive.length > 0) {
const now = Date.now();
if (now - lastPressTime >= LIVE_CONFIG.debounceDelay) {
keyDown('ArrowDown', false);
lastPressTime = now;
}
}
}, 1000);
logger.moduleReady('LIVE');
performanceTracker.end('LIVE_DETECTION');
}
const HIDE_CONFIG = {
textsToHide: ['充钻石', '客户端', '壁纸', '投稿', '更多'],
maxRetry: 5
};
let hideRetryCount = 0;
function hideElements() {
performanceTracker.start('ELEMENTS_HIDING');
logger.initModule('HIDE_ELEMENTS');
if (!FEATURE.HIDE_ELEMENTS) {
logger.moduleReady('HIDE_ELEMENTS');
performanceTracker.end('ELEMENTS_HIDING');
return;
}
let foundCount = 0;
document.querySelectorAll('.jenVD1aU, .iQdAxsPk, .xgplayer-playswitch').forEach(item => {
const text = (item.textContent || '').trim();
if (HIDE_CONFIG.textsToHide.some(t => text.includes(t))) {
const parent = item.closest('.Xu0nlrYh') || item.closest('div');
if (parent) {
parent.style.visibility = 'hidden';
parent.style.opacity = '0';
parent.style.pointerEvents = 'none';
foundCount++;
}
}
});
const wallpaper = document.querySelector('.xFzvM6nY, .iQdAxsPk');
if (wallpaper) {
const p = wallpaper.closest('div');
if (p) {
p.style.visibility = 'hidden';
foundCount++;
}
}
if (foundCount < 4 && hideRetryCount < HIDE_CONFIG.maxRetry) {
hideRetryCount++;
setTimeout(hideElements, 3000);
}
logger.moduleReady('HIDE_ELEMENTS');
performanceTracker.end('ELEMENTS_HIDING');
}
function setupElementHider() {
performanceTracker.start('ELEMENTS_MONITOR');
logger.initModule('HIDE_ELEMENTS');
if (!FEATURE.HIDE_ELEMENTS) {
logger.moduleReady('HIDE_ELEMENTS');
performanceTracker.end('ELEMENTS_MONITOR');
return;
}
let checkInterval = null;
let successCount = 0;
function hideElementsPersistent() {
let foundCount = 0;
document.querySelectorAll('.jenVD1aU, .iQdAxsPk').forEach(item => {
const text = (item.textContent || '').trim();
if (HIDE_CONFIG.textsToHide.some(t => text.includes(t))) {
const parent = item.closest('.Xu0nlrYh') || item.closest('div');
if (parent && parent.style.display !== 'none') {
parent.style.display = 'none';
foundCount++;
}
}
});
const wallpapers = document.querySelectorAll('.xFzvM6nY, .iQdAxsPk');
wallpapers.forEach(wallpaper => {
const parent = wallpaper.closest('div');
if (parent && parent.style.display !== 'none') {
parent.style.display = 'none';
foundCount++;
}
});
if (foundCount > 0) {
successCount++;
if (successCount > 3 && checkInterval) {
clearInterval(checkInterval);
checkInterval = setInterval(hideElementsPersistent, 5000);
}
}
}
hideElementsPersistent();
checkInterval = setInterval(hideElementsPersistent, 1000);
const observer = new MutationObserver(hideElementsPersistent);
if (document.body) {
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class']
});
}
logger.moduleReady('HIDE_ELEMENTS');
performanceTracker.end('ELEMENTS_MONITOR');
}
const AD_CONFIG = {
blockedKeywords: ['影视', '电影', '电视剧', '观影', '好剧', '狂飙'],
blockedAuthors: ['@王者荣耀'],
debounceDelay: 3000,
stableTries: 6,
stableGap: 80
};
try {
const kw = localStorage.getItem('xyDYTools_ads_keywords');
if (kw) AD_CONFIG.blockedKeywords = kw.split(/[\n,,]+/g).map(v => v.trim()).filter(Boolean);
} catch (_) {}
try {
const ba = localStorage.getItem('xyDYTools_ads_blockedAuthors');
if (ba) AD_CONFIG.blockedAuthors = ba.split(/[\n,,]+/g).map(v => v.trim()).filter(Boolean);
} catch (_) {}
let lastSkipTime = 0;
let adObserver = null;
let adCheckTimer = null;
function pickBestBySelector(selector) {
const list = Array.from(document.querySelectorAll(selector));
if (!list.length) return null;
let best = null;
let bestScore = -Infinity;
for (const el of list) {
if (!isVisible(el)) continue;
const r = el.getBoundingClientRect();
const area = r.width * r.height;
const score = area * 0.001 + (window.innerHeight - r.bottom) * 0.5 + (window.innerWidth - r.left) *
0.05;
if (score > bestScore) {
bestScore = score;
best = el;
}
}
return best;
}
function getVideoDescriptionNow() {
const el = pickBestBySelector('[data-e2e="video-desc"]');
if (!el) return '';
return normText(el.textContent);
}
async function getVideoDescriptionStable() {
let last = '';
for (let i = 0; i < AD_CONFIG.stableTries; i++) {
if (i > 0) await sleep(AD_CONFIG.stableGap);
const cur = getVideoDescriptionNow();
if (!cur) {
last = '';
continue;
}
await sleep(AD_CONFIG.stableGap);
const cur2 = getVideoDescriptionNow();
if (cur2 && cur2 === cur) return cur2;
last = cur2 || cur;
}
return last;
}
function getAuthorIdNow() {
const el = pickBestBySelector('[data-e2e="feed-video-nickname"]');
if (!el) return '';
return normText(el.textContent);
}
async function getAuthorIdStable() {
let last = '';
for (let i = 0; i < AD_CONFIG.stableTries; i++) {
if (i > 0) await sleep(AD_CONFIG.stableGap);
const cur = getAuthorIdNow();
if (!cur) {
last = '';
continue;
}
await sleep(AD_CONFIG.stableGap);
const cur2 = getAuthorIdNow();
if (cur2 && cur2 === cur) return cur2;
last = cur2 || cur;
}
return last;
}
function showBlockNotice(reason) {
if (!FEATURE.ADS) return;
const notice = document.createElement('div');
notice.textContent = `[屏蔽] ${reason}`;
Object.assign(notice.style, {
position: 'fixed',
bottom: '20px',
left: '50%',
transform: 'translateX(-50%)',
background: 'rgba(0,0,0,0.7)',
color: '#fff',
padding: '8px 12px',
borderRadius: '20px',
zIndex: 9999,
fontSize: '14px',
maxWidth: '80%'
});
document.body.appendChild(notice);
setTimeout(() => notice.remove(), 2000);
}
function hitKeyword(desc) {
const d = String(desc || '').toLowerCase();
return AD_CONFIG.blockedKeywords.find(k => d.includes(String(k).toLowerCase())) || '';
}
function hitAuthor(author) {
const a = normText(author).toLowerCase();
if (!a) return '';
for (const raw of (AD_CONFIG.blockedAuthors || [])) {
const p = normText(raw).toLowerCase();
if (!p) continue;
if (a.includes(p)) return raw;
}
return '';
}
function skipVideo(reasonText) {
const now = Date.now();
if (now - lastSkipTime < AD_CONFIG.debounceDelay) return;
lastSkipTime = now;
try {
keyDown('r', false);
} catch (_) {}
try {
keyUp('r');
} catch (_) {}
if (reasonText) showBlockNotice(reasonText);
}
async function checkAndHandleVideo() {
if (!FEATURE.ADS) return;
const [desc, author] = await Promise.all([
getVideoDescriptionStable(),
getAuthorIdStable()
]);
const a = hitAuthor(author);
if (a) {
skipVideo(`作者命中:${a}`);
return;
}
const k1 = hitKeyword(desc);
const k2 = hitKeyword(author);
if (k1 || k2) skipVideo(`关键词命中:"${k1 || k2}"`);
}
function scheduleAdCheck() {
if (!FEATURE.ADS) return;
if (adCheckTimer) return;
adCheckTimer = setTimeout(async () => {
adCheckTimer = null;
try {
await checkAndHandleVideo();
} catch (_) {}
}, 120);
}
function observeVideo() {
performanceTracker.start('ADS_OBSERVER');
logger.initModule('ADS');
if (!FEATURE.ADS) {
logger.moduleReady('ADS');
performanceTracker.end('ADS_OBSERVER');
return;
}
if (adObserver) adObserver.disconnect();
const target = document.body || document.documentElement;
if (!target) {
setTimeout(observeVideo, 800);
return;
}
adObserver = new MutationObserver(() => scheduleAdCheck());
adObserver.observe(target, {
childList: true,
subtree: true
});
scheduleAdCheck();
logger.moduleReady('ADS');
performanceTracker.end('ADS_OBSERVER');
}
window.xyDYTools = window.xyDYTools || {};
window.xyDYTools.getDescNow = function() {
return getVideoDescriptionNow();
};
window.xyDYTools.getDescStable = async function() {
return await getVideoDescriptionStable();
};
window.xyDYTools.getAuthorNow = function() {
return getAuthorIdNow();
};
window.xyDYTools.getAuthorStable = async function() {
return await getAuthorIdStable();
};
window.xyDYTools.forceCheck = async function() {
await checkAndHandleVideo();
return 'checked';
};
window.xyDYTools.setBlockedAuthors = function(arr) {
AD_CONFIG.blockedAuthors = Array.isArray(arr) ? arr : AD_CONFIG.blockedAuthors;
return AD_CONFIG.blockedAuthors;
};
window.xyDYTools.addBlockedAuthor = function(one) {
const v = normText(one);
if (!v) return AD_CONFIG.blockedAuthors;
if (!AD_CONFIG.blockedAuthors.some(x => normText(x) === v)) AD_CONFIG.blockedAuthors.push(v);
return AD_CONFIG.blockedAuthors;
};
window.xyDYTools.listAllDescNodes = function() {
const list = Array.from(document.querySelectorAll('[data-e2e="video-desc"]'));
return list.map((el, i) => {
const r = el.getBoundingClientRect();
return {
index: i,
text: normText(el.textContent),
visible: isVisible(el),
rect: {
top: r.top,
left: r.left,
width: r.width,
height: r.height
}
};
});
};
window.xyDYTools.listAllAuthorNodes = function() {
const list = Array.from(document.querySelectorAll('[data-e2e="feed-video-nickname"]'));
return list.map((el, i) => {
const r = el.getBoundingClientRect();
return {
index: i,
text: normText(el.textContent),
visible: isVisible(el),
rect: {
top: r.top,
left: r.left,
width: r.width,
height: r.height
}
};
});
};
window.xyDYTools.printADDebug = async function() {
const time = new Date().toLocaleTimeString();
const nowDesc = window.xyDYTools.getDescNow();
const nowAuthor = window.xyDYTools.getAuthorNow();
const stableDesc = await window.xyDYTools.getDescStable();
const stableAuthor = await window.xyDYTools.getAuthorStable();
console.log('==== AD DEBUG ====');
console.log('time:', time);
console.log('nowAuthor:', nowAuthor);
console.log('stableAuthor:', stableAuthor);
console.log('nowDesc:', nowDesc);
console.log('stableDesc:', stableDesc);
console.log('blockedAuthors:', AD_CONFIG.blockedAuthors);
console.log('blockedKeywords:', AD_CONFIG.blockedKeywords);
console.log('==================');
return {
time,
nowAuthor,
stableAuthor,
nowDesc,
stableDesc
};
};
const MOUSE_CONFIG = {
swipeThreshold: 200,
clickMaxMove: 5,
clickMaxTime: 300,
longPressTime: 500
};
let startX = 0;
let startY = 0;
let startTime = 0;
let isMouseDown = false;
let isSwiping = false;
let blockClick = false;
let longPressTimer = null;
let isLongPressing = false;
function mouseKeyDown(key, repeat) {
if (!FEATURE.MOUSE) return;
keyDown(key, repeat);
}
function mouseKeyUp(key) {
if (!FEATURE.MOUSE) return;
keyUp(key);
}
function likeVideo() {
const video = document.querySelector('video');
if (!video) return;
const wasPlaying = !video.paused;
mouseKeyDown('z', false);
if (wasPlaying) {
setTimeout(() => {
if (video.paused) video.play();
}, 100);
}
}
function handleSwipe(direction) {
if (!FEATURE.MOUSE) return;
if (direction === 'left') likeVideo();
if (direction === 'right') mouseKeyDown('r', false);
}
document.addEventListener('mousedown', function(e) {
if (!FEATURE.MOUSE) return;
startX = e.clientX;
startY = e.clientY;
startTime = Date.now();
isMouseDown = true;
isSwiping = false;
blockClick = false;
isLongPressing = false;
if (e.button === 1) {
e.preventDefault();
e.stopPropagation();
mouseKeyDown('x', false);
return;
}
if (e.button === 0) {
longPressTimer = setTimeout(() => {
if (isMouseDown && !isSwiping) {
isLongPressing = true;
blockClick = true;
mouseKeyDown('d', true);
}
}, MOUSE_CONFIG.longPressTime);
}
}, true);
document.addEventListener('mousemove', function(e) {
if (!FEATURE.MOUSE) return;
if (!isMouseDown) return;
if (isLongPressing) return;
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
if (!isSwiping) {
if (Math.abs(deltaX) > MOUSE_CONFIG.swipeThreshold || Math.abs(deltaY) > MOUSE_CONFIG
.swipeThreshold) {
isSwiping = true;
blockClick = true;
if (longPressTimer) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
const direction = Math.abs(deltaX) > Math.abs(deltaY) ?
(deltaX > 0 ? 'right' : 'left') :
(deltaY > 0 ? 'down' : 'up');
handleSwipe(direction);
}
}
}, true);
document.addEventListener('mouseup', function(e) {
if (!FEATURE.MOUSE) return;
if (!isMouseDown) return;
if (e.button === 0) {
if (longPressTimer) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
if (isLongPressing) {
mouseKeyUp('d');
e.preventDefault();
e.stopPropagation();
}
}
const endX = e.clientX;
const endY = e.clientY;
const deltaX = endX - startX;
const deltaY = endY - startY;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
const duration = Date.now() - startTime;
if (distance >= MOUSE_CONFIG.clickMaxMove || duration >= MOUSE_CONFIG.clickMaxTime || isSwiping ||
isLongPressing) {
e.preventDefault();
e.stopPropagation();
}
isMouseDown = false;
isSwiping = false;
isLongPressing = false;
setTimeout(() => {
blockClick = false;
}, 50);
}, true);
document.addEventListener('click', function(e) {
if (!FEATURE.MOUSE) return;
if (blockClick) {
e.stopPropagation();
e.preventDefault();
}
}, true);
document.addEventListener('keydown', (e) => {
if (!e.altKey || e.ctrlKey || e.shiftKey) return;
const key = e.key.toUpperCase();
if (key === '1') {
e.preventDefault();
e.stopPropagation();
setSidebarLock(!isSidebarLocked());
}
}, true);
function initSettingsModal() {
(function injectUIStyle() {
if (document.getElementById('xydytools-ui-style')) return;
const style = document.createElement('style');
style.id = 'xydytools-ui-style';
style.textContent = `
#xydytools-modal{position:fixed;inset:0;z-index:9999999;display:none;}
#xydytools-modal.show{display:block;}
#xydytools-modal .mask{position:absolute;inset:0;background:rgba(0,0,0,0.55);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);}
#xydytools-modal .panel{
position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
width:min(520px, 92vw);
max-height:min(640px, 82vh);
overflow:auto;
background:rgba(255,255,255,0.28);
border:1px solid rgba(255,255,255,0.55);
border-radius:16px;
box-shadow:0 16px 60px rgba(0,0,0,0.25), inset 0 1px 0 rgba(255,255,255,0.55);
color:rgba(0,0,0,0.88);
}
#xydytools-modal .hd{
position:sticky;top:0;z-index:1;
display:flex;align-items:center;justify-content:space-between;gap:12px;
padding:14px 14px 10px;
background:linear-gradient(to bottom, rgba(255,255,255,0.38), rgba(255,255,255,0.18));
backdrop-filter:blur(10px) saturate(180%);
-webkit-backdrop-filter:blur(10px) saturate(180%);
border-bottom:1px solid rgba(255,255,255,0.35);
border-top-left-radius:16px;border-top-right-radius:16px;
}
#xydytools-modal .title{display:flex;align-items:center;gap:10px;font-weight:800;letter-spacing:0.2px;}
#xydytools-modal .sub{margin-left:26px;margin-top:2px;font-size:12px;color:rgba(0,0,0,0.55);}
#xydytools-modal .close{
width:34px;height:34px;border-radius:12px;
display:flex;align-items:center;justify-content:center;
cursor:pointer;user-select:none;
background:rgba(255,255,255,0.35);
border:1px solid rgba(255,255,255,0.45);
transition:transform .12s ease, background .12s ease;
}
#xydytools-modal .close:hover{background:rgba(255,255,255,0.48);transform:translateY(-1px);}
#xydytools-modal .close:active{transform:translateY(0px) scale(0.98);}
#xydytools-modal .bd{padding:12px 14px 14px;}
#xydytools-modal .hint{
font-size:12px;color:rgba(0,0,0,0.58);
padding:10px 12px;border-radius:12px;
background:rgba(255,255,255,0.26);
border:1px solid rgba(255,255,255,0.35);
margin-bottom:12px;
}
#xydytools-modal .list{display:flex;flex-direction:column;gap:10px;}
#xydytools-modal .row{
display:flex;align-items:center;justify-content:space-between;gap:12px;
padding:10px 12px;border-radius:14px;
background:rgba(255,255,255,0.22);
border:1px solid rgba(255,255,255,0.32);
}
#xydytools-modal .row .l{display:flex;flex-direction:column;gap:4px;min-width:0;}
#xydytools-modal .row .name{font-weight:700;font-size:14px;}
#xydytools-modal .row .desc{
font-size:12px;color:rgba(0,0,0,0.55);
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
max-width:320px;
}
#xydytools-modal .toggle{position:relative;display:inline-block;width:58px;height:32px;}
#xydytools-modal .toggle input{opacity:0;width:0;height:0;position:absolute;}
#xydytools-modal .slider{
position:absolute;inset:0;background:#d1d1d6;border-radius:999px;
cursor:pointer;-webkit-tap-highlight-color:transparent;user-select:none;
transition:background .2s .25s;
}
#xydytools-modal .slider:before{
content:'';position:absolute;top:3px;left:3px;width:26px;height:26px;border-radius:50%;
background:#fff;box-shadow:0 2px 6px rgba(0,0,0,.2);
transition:transform .25s cubic-bezier(.4,0,.2,1);
}
#xydytools-modal .toggle input:checked + .slider{background:#34c759;}
#xydytools-modal .toggle input:checked + .slider:before{transform:translateX(26px);}
#xydytools-modal .toggle input:focus + .slider{box-shadow:0 0 0 3px rgba(52,199,89,.3);}
#xydytools-modal .adsBox{
margin-top:10px;
padding:10px 12px;
border-radius:14px;
background:rgba(255,255,255,0.20);
border:1px solid rgba(255,255,255,0.30);
display:none;
}
#xydytools-modal .adsBox.show{display:block;}
#xydytools-modal .adsBox .t{font-weight:800;font-size:13px;margin-bottom:6px;}
#xydytools-modal .adsBox .d{font-size:12px;color:rgba(0,0,0,0.55);margin-bottom:8px;line-height:1.4;}
#xydytools-modal .adsBox textarea{
width:100%;
min-height:74px;
resize:vertical;
padding:10px 10px;
border-radius:12px;
background:rgba(255,255,255,0.35);
border:1px solid rgba(255,255,255,0.45);
outline:none;
color:rgba(0,0,0,0.88);
font-size:12px;
line-height:1.45;
}
#xydytools-modal .adsBox textarea:focus{box-shadow:0 0 0 3px rgba(52,199,89,.20);}
#xydytools-modal .adsBox .ops{display:flex;gap:10px;margin-top:8px;align-items:center;}
#xydytools-modal .adsBox .btn{
padding:7px 12px;
border-radius:999px;
background:rgba(0,0,0,0.75);
color:#fff;
border:1px solid rgba(255,255,255,0.25);
cursor:pointer;
user-select:none;
font-size:12px;
}
#xydytools-modal .adsBox .btn:active{transform:scale(0.98);}
#xydytools-modal .adsBox .tip{font-size:12px;color:rgba(0,0,0,0.55);}
`;
(document.head || document.documentElement).appendChild(style);
})();
const FEATURE_META = [{
k: 'SIDEBAR',
name: '侧栏',
desc: '隐藏/悬停弹出/锁定隐藏'
},
{
k: 'STYLES',
name: '样式美化',
desc: '玻璃拟态 + 播放器控件优化'
},
{
k: 'NAVIGATION',
name: '顶部栏智能',
desc: '靠近顶部显示,离开自动收起'
},
{
k: 'LIVE',
name: '直播跳过(未实装)',
desc: '检测直播标识并跳过'
},
{
k: 'HIDE_ELEMENTS',
name: '隐藏杂项',
desc: '充钻石/壁纸/投稿等'
},
{
k: 'ADS',
name: '关键词屏蔽',
desc: '作者信息,视频信息命中关键词就跳过'
},
{
k: 'MOUSE',
name: '鼠标手势',
desc: '左滑点赞/右滑R/中键X/左键长按D'
},
{
k: 'LOADING',
name: '加载遮罩',
desc: '加载提示层'
},
{
k: 'PERFORMANCE',
name: '性能统计',
desc: '模块耗时统计与报告'
}
];
function ensureModal() {
let modal = document.getElementById('xydytools-modal');
if (modal) return modal;
modal = document.createElement('div');
modal.id = 'xydytools-modal';
modal.innerHTML = `
有些开关改完建议刷新页面(比如已经启动的定时检测/观察者)。
`;
document.documentElement.appendChild(modal);
const hide = () => {
modal.classList.remove('show');
document.documentElement.style.overflow = '';
};
modal.querySelector('.mask').addEventListener('click', hide, true);
modal.querySelector('.close').addEventListener('click', hide, true);
window.addEventListener('keydown', (e) => {
if (modal.classList.contains('show') && e.key === 'Escape') {
e.preventDefault();
e.stopPropagation();
hide();
}
}, true);
return modal;
}
function renderModal() {
const modal = ensureModal();
const list = modal.querySelector('#xydytools-list');
list.innerHTML = '';
FEATURE_META.forEach(item => {
const row = document.createElement('div');
row.className = 'row';
row.innerHTML = `
${item.name}
${item.desc}
`;
list.appendChild(row);
const input = row.querySelector('input');
if (item.k === 'ADS') {
const LS_ADS_KW = 'xyDYTools_ads_keywords';
const LS_ADS_AUTH = 'xyDYTools_ads_blockedAuthors';
function parseList(s) {
return String(s || '').split(/[\n,,]+/g).map(v => v.trim()).filter(Boolean);
}
function joinList(arr) {
return (Array.isArray(arr) ? arr : []).join('\n');
}
let kw = [];
let ba = [];
try {
const kwRaw = localStorage.getItem(LS_ADS_KW);
kw = kwRaw ? parseList(kwRaw) : (AD_CONFIG.blockedKeywords || []);
} catch (_) {
kw = (AD_CONFIG.blockedKeywords || []);
}
try {
const baRaw = localStorage.getItem(LS_ADS_AUTH);
ba = baRaw ? parseList(baRaw) : (AD_CONFIG.blockedAuthors || []);
} catch (_) {
ba = (AD_CONFIG.blockedAuthors || []);
}
const box = document.createElement('div');
box.className = 'adsBox' + (FEATURE.ADS ? ' show' : '');
box.innerHTML = `
关键词库(简介 + 作者名共用)
一行一个;支持逗号分隔。命中就屏蔽。
作者黑名单(可选)
填作者名关键词,命中就屏蔽。
`;
list.appendChild(box);
const kwEl = box.querySelector('textarea.kw');
const baEl = box.querySelector('textarea.ba');
function applyToConfig() {
AD_CONFIG.blockedKeywords = parseList(kwEl.value);
AD_CONFIG.blockedAuthors = parseList(baEl.value);
}
box.querySelector('.save').addEventListener('click', () => {
try {
localStorage.setItem(LS_ADS_KW, kwEl.value);
} catch (_) {}
try {
localStorage.setItem(LS_ADS_AUTH, baEl.value);
} catch (_) {}
applyToConfig();
try {
scheduleAdCheck();
} catch (_) {}
}, true);
box.querySelector('.reset').addEventListener('click', () => {
kwEl.value = joinList(['影视', '电影', '电视剧', '观影', '好剧', '狂飙']);
baEl.value = joinList(['@王者荣耀']);
try {
localStorage.removeItem(LS_ADS_KW);
} catch (_) {}
try {
localStorage.removeItem(LS_ADS_AUTH);
} catch (_) {}
applyToConfig();
try {
scheduleAdCheck();
} catch (_) {}
}, true);
input.addEventListener('change', () => box.classList.toggle('show', !!FEATURE.ADS),
true);
}
input.addEventListener('change', () => {
const v = input.checked ? 1 : 0;
FEATURE[item.k] = v;
try {
localStorage.setItem(LS_PREFIX + item.k, String(v));
} catch (_) {}
if (item.k === 'STYLES') {
if (!v) {
try {
document.getElementById('douyin-dynamic-styles')?.remove();
} catch (_) {}
try {
document.getElementById('douyin-safe-styles')?.remove();
} catch (_) {}
} else {
try {
injectStyles();
} catch (_) {}
try {
injectSafeStyles();
} catch (_) {}
}
}
if (item.k === 'NAVIGATION') {
if (!v) {
document.documentElement.classList.remove('tm-nav-autohide');
const h = document.getElementById('douyin-header');
if (h) h.classList.add('show');
} else {
try {
initTopNavigation();
} catch (_) {}
}
}
if (item.k === 'ADS') {
if (!v) {
try {
adObserver && adObserver.disconnect();
} catch (_) {}
} else {
try {
observeVideo();
checkAndHandleVideo();
} catch (_) {}
}
}
if (item.k === 'LIVE') {
if (!v) {
try {
liveCheckInterval && clearInterval(liveCheckInterval);
} catch (_) {}
} else {
try {
startLiveCheck();
} catch (_) {}
}
}
}, true);
});
}
function showModal() {
const modal = ensureModal();
renderModal();
modal.classList.add('show');
document.documentElement.style.overflow = 'hidden';
}
window.addEventListener('keydown', (e) => {
if (!e.altKey || e.ctrlKey || e.shiftKey) return;
if ((e.key || '').toLowerCase() !== 'x') return;
e.preventDefault();
e.stopPropagation();
showModal();
}, true);
}
(function dySilentDislikeAndNoLive() {
if (window.__dySilentMenuBound) return;
window.__dySilentMenuBound = true;
let running = false;
document.addEventListener('mousemove', (e) => {
window.__dyLastMouseX = e.clientX;
window.__dyLastMouseY = e.clientY;
}, true);
(function injectSilentMenuStyle() {
if (document.getElementById('dy-silent-menu-style')) return;
const style = document.createElement('style');
style.id = 'dy-silent-menu-style';
style.textContent =
`html.dy-silent-menu div[id="qgmiQqfW"]{opacity:0 !important;transition:none !important;}`;
(document.head || document.documentElement).appendChild(style);
})();
function fireFullClick(el) {
if (!el) return false;
el.dispatchEvent(new MouseEvent('mousemove', {
bubbles: true
}));
el.dispatchEvent(new MouseEvent('mousedown', {
bubbles: true,
button: 0,
buttons: 1
}));
el.dispatchEvent(new MouseEvent('mouseup', {
bubbles: true,
button: 0,
buttons: 0
}));
el.click();
return true;
}
function findMenuItemByText(text) {
const nodes = Array.from(document.querySelectorAll('.JyNO_DD4'));
return nodes.find(n => (n.textContent || '').trim() === text) || null;
}
function waitMenuItem(text, timeoutMs) {
return new Promise(resolve => {
const t0 = Date.now();
const hit = findMenuItemByText(text);
if (hit) return resolve(hit);
const ob = new MutationObserver(() => {
const n = findMenuItemByText(text);
if (n) {
ob.disconnect();
resolve(n);
} else if (Date.now() - t0 > timeoutMs) {
ob.disconnect();
resolve(null);
}
});
ob.observe(document.documentElement, {
childList: true,
subtree: true
});
setTimeout(() => {
ob.disconnect();
resolve(findMenuItemByText(text));
}, timeoutMs + 50);
});
}
function triggerRightClick() {
let x = window.__dyLastMouseX;
let y = window.__dyLastMouseY;
if (typeof x !== 'number' || typeof y !== 'number') {
x = Math.floor(window.innerWidth * 0.5);
y = Math.floor(window.innerHeight * 0.5);
}
const el = document.elementFromPoint(x, y) || document.body;
const down = {
bubbles: true,
cancelable: true,
view: window,
button: 2,
buttons: 2,
clientX: x,
clientY: y
};
const up = {
bubbles: true,
cancelable: true,
view: window,
button: 2,
buttons: 0,
clientX: x,
clientY: y
};
el.dispatchEvent(new MouseEvent('mousedown', down));
el.dispatchEvent(new MouseEvent('contextmenu', down));
el.dispatchEvent(new MouseEvent('mouseup', up));
document.dispatchEvent(new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
view: window,
button: 0,
buttons: 0,
clientX: x,
clientY: y
}));
}
async function runSilentBlock() {
if (running) return;
running = true;
try {
document.documentElement.classList.add('dy-silent-menu');
triggerRightClick();
const a = await waitMenuItem('不感兴趣', 2500);
if (a) fireFullClick(a);
await sleep(80);
const b = await waitMenuItem('不想看直播', 2500);
if (b) fireFullClick(b);
} finally {
setTimeout(() => {
document.documentElement.classList.remove('dy-silent-menu');
running = false;
}, 200);
}
}
document.addEventListener('keydown', (e) => {
if (e.altKey && !e.ctrlKey && !e.shiftKey && (e.key === 'f' || e.key === 'F')) {
e.preventDefault();
e.stopPropagation();
runSilentBlock();
}
}, true);
})();
function initializeScript() {
performanceTracker.start('TOTAL_INIT');
createLoadingScreen();
try {
initSidebarToggle();
} catch (_) {}
try {
injectStyles();
window.__xyDYToolsBoot.styles = true;
} catch (_) {}
try {
injectSafeStyles();
window.__xyDYToolsBoot.safeStyles = true;
} catch (_) {}
try {
initSettingsModal();
} catch (_) {}
if (window.location.host === 'www.douyin.com') {
try {
initTopNavigation();
window.__xyDYToolsBoot.nav = true;
} catch (_) {}
}
try {
hideElements();
window.__xyDYToolsBoot.hide = true;
} catch (_) {}
try {
observeVideo();
window.__xyDYToolsBoot.ads = true;
} catch (_) {}
try {
checkAndHandleVideo();
} catch (_) {}
window.__xyDYToolsBoot.inited = true;
try {
startLiveCheck();
} catch (_) {}
if (document.readyState === 'complete') setupElementHider();
else window.addEventListener('load', setupElementHider);
setTimeout(() => {
performanceTracker.printPerformanceReport();
performanceTracker.end('TOTAL_INIT');
}, 2000);
}
initializeScript();
window.douyinPerformance = performanceTracker;
})();