// ==UserScript== // @name 防切屏暂停视频 + 解除复制限制 + 解除F12拦截 + 视频倍速控制 // @namespace ckxgzxa // @version 1.1 // @description 拦截页面可见性检测,伪装网页始终处于前台;解除网页复制限制;解除F12及开发者工具拦截;增加视频倍速1.5x/1.75x/2x控制 // @author ckxgzxa // @match *://*.excnpc.com/* // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; // ==================== 核心:重写页面可见性相关属性 ==================== const overrideVisibilityProps = () => { Object.defineProperty(document, 'visibilityState', { get: () => 'visible', configurable: true }); Object.defineProperty(document, 'hidden', { get: () => false, configurable: true }); Object.defineProperty(document, 'webkitVisibilityState', { get: () => 'visible', configurable: true }); Object.defineProperty(document, 'webkitHidden', { get: () => false, configurable: true }); }; const blockVisibilityEvents = () => { const eventNames = [ 'visibilitychange', 'webkitvisibilitychange', 'mozvisibilitychange', 'msvisibilitychange' ]; eventNames.forEach(eventName => { const originalAddListener = document.addEventListener; document.addEventListener = function(type, listener, options) { if (type === eventName) return; return originalAddListener.call(this, type, listener, options); }; const originalDispatch = document.dispatchEvent; document.dispatchEvent = function(event) { if (event.type === eventName) return true; return originalDispatch.call(this, event); }; }); }; const fakePageActive = () => { Object.defineProperty(document, 'hasFocus', { value: () => true, configurable: true }); const originalAddWinListener = window.addEventListener; window.addEventListener = function(type, listener, options) { if (type === 'blur' || type === 'focusout') return; return originalAddWinListener.call(this, type, listener, options); }; window.addEventListener('blur', () => { window.focus(); }, { once: false }); }; // ==================== 解除复制限制 ==================== const unblockCopy = () => { const blockedEvents = ['copy', 'cut', 'contextmenu', 'selectstart', 'dragstart', 'mousedown', 'mouseup']; blockedEvents.forEach(evtName => { window.addEventListener(evtName, (e) => { e.stopPropagation(); }, true); }); const originalExecCommand = document.execCommand; document.execCommand = function(command, showUI, value) { const cmd = command.toLowerCase(); if (cmd === 'copy' || cmd === 'cut') { try { return originalExecCommand.call(this, command, showUI, value); } catch (e) { return false; } } return originalExecCommand.call(this, command, showUI, value); }; const clearInlineHandlers = () => { const attrs = ['oncopy', 'oncut', 'oncontextmenu', 'onselectstart', 'ondragstart']; const allElements = document.querySelectorAll('*'); allElements.forEach(el => { attrs.forEach(attr => { if (el.hasAttribute(attr)) { el.removeAttribute(attr); } }); }); if (document.body) { attrs.forEach(attr => document.body.removeAttribute(attr)); } if (document.documentElement) { attrs.forEach(attr => document.documentElement.removeAttribute(attr)); } }; const style = document.createElement('style'); style.textContent = ` * { -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; user-select: text !important; -webkit-touch-callout: default !important; } `; (document.head || document.documentElement).appendChild(style); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', clearInlineHandlers); } else { clearInlineHandlers(); } setInterval(clearInlineHandlers, 2000); }; // ==================== 解除 F12 / 开发者工具拦截 ==================== const unblockDevTools = () => { const blockedKeys = [ { key: 'F12', code: 'F12', keyCode: 123 }, { ctrlKey: true, shiftKey: true, key: 'I', code: 'KeyI', keyCode: 73 }, { ctrlKey: true, shiftKey: true, key: 'J', code: 'KeyJ', keyCode: 74 }, { ctrlKey: true, shiftKey: true, key: 'C', code: 'KeyC', keyCode: 67 }, { ctrlKey: true, key: 'U', code: 'KeyU', keyCode: 85 } ]; window.addEventListener('keydown', (e) => { for (const combo of blockedKeys) { let match = true; if (combo.key !== undefined && e.key !== combo.key) match = false; if (combo.code !== undefined && e.code !== combo.code) match = false; if (combo.keyCode !== undefined && e.keyCode !== combo.keyCode) match = false; if (combo.ctrlKey !== undefined && e.ctrlKey !== combo.ctrlKey) match = false; if (combo.shiftKey !== undefined && e.shiftKey !== combo.shiftKey) match = false; if (match) { e.stopPropagation(); return; } } }, true); window.addEventListener('beforeunload', (e) => { e.stopImmediatePropagation(); }, true); const originalSetInterval = window.setInterval; const originalSetTimeout = window.setTimeout; window.setInterval = function(func, delay, ...args) { if (typeof func === 'function') { const funcStr = func.toString(); if (funcStr === 'function(){debugger}' || funcStr === '()=>{debugger}' || /^\s*function\s*\(\)\s*\{\s*debugger\s*;?\s*\}\s*$/.test(funcStr)) { return -1; } } return originalSetInterval.call(this, func, delay, ...args); }; window.setTimeout = function(func, delay, ...args) { if (typeof func === 'function') { const funcStr = func.toString(); if (funcStr === 'function(){debugger}' || funcStr === '()=>{debugger}' || /^\s*function\s*\(\)\s*\{\s*debugger\s*;?\s*\}\s*$/.test(funcStr)) { return -1; } } return originalSetTimeout.call(this, func, delay, ...args); }; const originalEval = window.eval; window.eval = function(code) { if (typeof code === 'string') { code = code.replace(/\bdebugger\b\s*;?/g, ''); } return originalEval.call(this, code); }; const originalClear = console.clear; console.clear = function() { console.log('[UserScript] 页面尝试清空控制台,已拦截'); }; }; // ==================== 新增:视频倍速控制面板 ==================== const initVideoSpeedControl = () => { const SPEEDS = [ { label: '0.5x', value: 0.5 }, { label: '0.75x', value: 0.75 }, { label: '1.0x', value: 1.0 }, { label: '1.25x', value: 1.25 }, { label: '1.5x', value: 1.5 }, { label: '1.75x', value: 1.75 }, { label: '2.0x', value: 2.0 }, { label: '2.5x', value: 2.5 }, { label: '3.0x', value: 3.0 } ]; let currentSpeed = 1.0; let speedPanel = null; let activeBtn = null; // 创建倍速控制面板 const createPanel = () => { if (speedPanel) return; const panel = document.createElement('div'); panel.id = 'userscript-speed-panel'; panel.style.cssText = ` position: fixed; top: 100px; right: 20px; z-index: 999999; background: rgba(0, 0, 0, 0.85); border-radius: 8px; padding: 10px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 13px; color: #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.4); user-select: none; min-width: 120px; backdrop-filter: blur(4px); border: 1px solid rgba(255,255,255,0.1); `; // 标题 const title = document.createElement('div'); title.textContent = '⚡ 视频倍速'; title.style.cssText = ` text-align: center; margin-bottom: 8px; font-weight: bold; color: #4fc3f7; font-size: 14px; border-bottom: 1px solid rgba(255,255,255,0.2); padding-bottom: 6px; `; panel.appendChild(title); // 倍速按钮容器 const btnContainer = document.createElement('div'); btnContainer.style.cssText = ` display: flex; flex-direction: column; gap: 4px; `; SPEEDS.forEach(speed => { const btn = document.createElement('button'); btn.textContent = speed.label; btn.dataset.speed = speed.value; btn.style.cssText = ` background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.15); color: #fff; padding: 5px 10px; border-radius: 4px; cursor: pointer; font-size: 12px; transition: all 0.2s; text-align: center; `; btn.onmouseenter = () => { btn.style.background = 'rgba(79, 195, 247, 0.3)'; btn.style.borderColor = '#4fc3f7'; }; btn.onmouseleave = () => { if (parseFloat(btn.dataset.speed) !== currentSpeed) { btn.style.background = 'rgba(255,255,255,0.1)'; btn.style.borderColor = 'rgba(255,255,255,0.15)'; } }; btn.onclick = () => { setSpeed(speed.value); }; btnContainer.appendChild(btn); }); panel.appendChild(btnContainer); // 当前倍速显示 const currentDisplay = document.createElement('div'); currentDisplay.id = 'userscript-current-speed'; currentDisplay.textContent = '当前: 1.0x'; currentDisplay.style.cssText = ` text-align: center; margin-top: 8px; font-size: 12px; color: #81c784; border-top: 1px solid rgba(255,255,255,0.2); padding-top: 6px; `; panel.appendChild(currentDisplay); // 折叠按钮 const toggleBtn = document.createElement('div'); toggleBtn.textContent = '−'; toggleBtn.style.cssText = ` position: absolute; top: 5px; right: 8px; cursor: pointer; color: #aaa; font-size: 16px; line-height: 1; `; let collapsed = false; toggleBtn.onclick = () => { collapsed = !collapsed; btnContainer.style.display = collapsed ? 'none' : 'flex'; currentDisplay.style.display = collapsed ? 'none' : 'block'; title.style.display = collapsed ? 'none' : 'block'; toggleBtn.textContent = collapsed ? '+' : '−'; panel.style.minWidth = collapsed ? '30px' : '120px'; panel.style.padding = collapsed ? '5px' : '10px'; }; panel.appendChild(toggleBtn); // 拖拽功能 let isDragging = false; let dragOffsetX = 0; let dragOffsetY = 0; title.style.cursor = 'move'; title.onmousedown = (e) => { isDragging = true; dragOffsetX = e.clientX - panel.offsetLeft; dragOffsetY = e.clientY - panel.offsetTop; e.preventDefault(); }; document.addEventListener('mousemove', (e) => { if (!isDragging) return; panel.style.left = (e.clientX - dragOffsetX) + 'px'; panel.style.top = (e.clientY - dragOffsetY) + 'px'; panel.style.right = 'auto'; }); document.addEventListener('mouseup', () => { isDragging = false; }); document.body.appendChild(panel); speedPanel = panel; }; // 设置倍速 const setSpeed = (speed) => { currentSpeed = speed; const videos = document.querySelectorAll('video'); videos.forEach(video => { video.playbackRate = speed; }); // 更新按钮高亮 if (speedPanel) { const btns = speedPanel.querySelectorAll('button'); btns.forEach(btn => { const btnSpeed = parseFloat(btn.dataset.speed); if (btnSpeed === speed) { btn.style.background = 'rgba(79, 195, 247, 0.4)'; btn.style.borderColor = '#4fc3f7'; btn.style.color = '#4fc3f7'; } else { btn.style.background = 'rgba(255,255,255,0.1)'; btn.style.borderColor = 'rgba(255,255,255,0.15)'; btn.style.color = '#fff'; } }); const display = speedPanel.querySelector('#userscript-current-speed'); if (display) { display.textContent = `当前: ${speed}x`; } } console.log(`[UserScript] 视频倍速已设置为 ${speed}x`); }; // 监听视频元素变化,自动应用当前倍速 const observeVideos = () => { const observer = new MutationObserver((mutations) => { let hasNewVideo = false; mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.tagName === 'VIDEO') { hasNewVideo = true; node.playbackRate = currentSpeed; } else if (node.querySelectorAll) { const videos = node.querySelectorAll('video'); if (videos.length > 0) { hasNewVideo = true; videos.forEach(v => v.playbackRate = currentSpeed); } } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); }; // 快捷键支持 const initHotkeys = () => { document.addEventListener('keydown', (e) => { // 避免在输入框中触发 if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) { return; } switch(e.key) { case 'ArrowRight': if (e.ctrlKey) { e.preventDefault(); const nextSpeed = SPEEDS.find(s => s.value > currentSpeed); if (nextSpeed) setSpeed(nextSpeed.value); } break; case 'ArrowLeft': if (e.ctrlKey) { e.preventDefault(); const prevIndex = SPEEDS.findIndex(s => s.value === currentSpeed); if (prevIndex > 0) setSpeed(SPEEDS[prevIndex - 1].value); } break; case 's': if (e.ctrlKey) { e.preventDefault(); if (speedPanel) { speedPanel.style.display = speedPanel.style.display === 'none' ? 'block' : 'none'; } } break; } }); }; // 初始化 const init = () => { if (!document.body) { setTimeout(init, 100); return; } createPanel(); observeVideos(); initHotkeys(); // 对已有视频立即应用 const existingVideos = document.querySelectorAll('video'); existingVideos.forEach(v => v.playbackRate = currentSpeed); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } }; // ==================== 执行所有逻辑 ==================== overrideVisibilityProps(); blockVisibilityEvents(); fakePageActive(); unblockCopy(); unblockDevTools(); initVideoSpeedControl(); // 动态监测重置 setInterval(() => { overrideVisibilityProps(); fakePageActive(); }, 1000); })();