// ==UserScript== // @name 矿大课堂回放视频去水印(强化版) // @namespace http://tampermonkey.net/ // @version 2.0 // @description 自动移除教学平台视频页面的水印,支持动态加载 // @match http://class.cumt.edu.cn/TeachingCenterStudentWeb/index.html // @match https://class.cumt.edu.cn/TeachingCenterStudentWeb/index.html // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // ---------- 水印检测函数(宽松版) ---------- function isWatermark(el) { if (!el || el.tagName !== 'DIV') return false; // 1. 优先检查类名是否以 "videoId" 开头(非常强的特征) if (el.className && typeof el.className === 'string' && el.className.startsWith('videoId')) { // 进一步校验样式(确保不是误删) const style = el.style; if (style.position === 'absolute' && parseFloat(style.opacity) === 0.38 && style.zIndex === '999' && style.backgroundImage && style.backgroundImage.includes('data:image')) { return true; } // 如果类名符合,但样式可能被类覆盖?但内联样式存在,我们仍然可以删除(因为类名很特殊) // 为安全起见,只要类名匹配且背景是base64图片就认为水印 if (style.backgroundImage && style.backgroundImage.includes('data:image')) { return true; } } // 2. 备用方案:通过内联样式特征匹配(不依赖类名) const style = el.style; if (style.position === 'absolute' && parseFloat(style.opacity) === 0.38 && style.zIndex === '999' && style.pointerEvents === 'none' && style.backgroundImage && style.backgroundImage.includes('data:image/png;base64')) { return true; } return false; } // ---------- 删除水印 ---------- function removeWatermarks() { let removed = 0; // 方法1:通过类名选择器快速查找 const candidates = document.querySelectorAll('[class^="videoId"]'); for (const el of candidates) { if (isWatermark(el)) { el.remove(); removed++; } } // 方法2:遍历所有 div,防止类名不完全匹配(例如类名包含videoId但不以它开头?) const allDivs = document.querySelectorAll('div'); for (const el of allDivs) { if (!el.parentNode) continue; // 已移除 if (isWatermark(el)) { el.remove(); removed++; } } if (removed > 0) { console.log(`[去水印] 成功删除 ${removed} 个水印元素`); } return removed; } // ---------- 初始化执行 ---------- // 等待 DOM 稳定 let initTimer = setTimeout(() => { removeWatermarks(); }, 500); // ---------- 监听动态变化 ---------- const observer = new MutationObserver((mutations) => { let needScan = false; for (const mut of mutations) { if (mut.type === 'childList' && mut.addedNodes.length > 0) { needScan = true; break; } if (mut.type === 'attributes' && (mut.attributeName === 'style' || mut.attributeName === 'class')) { needScan = true; break; } } if (needScan) { // 使用 requestAnimationFrame 或短延迟避免频繁扫描 clearTimeout(window._scanTimer); window._scanTimer = setTimeout(removeWatermarks, 100); } }); observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); // ---------- 定期轮询(兜底) ---------- const intervalId = setInterval(removeWatermarks, 3000); // ---------- 清理资源 ---------- window.addEventListener('beforeunload', () => { clearInterval(intervalId); clearTimeout(initTimer); observer.disconnect(); }); console.log('[去水印] 强化版脚本已启动,将自动移除水印。'); })();