解锁强制复制,取消所有网站【禁止复制】和【禁止粘贴】限制,支持【免费OCR识别】
// ==UserScript== // @name 文字助手-2025新年贺岁版 // @version 2.1 // @description 解锁强制复制,取消所有网站【禁止复制】和【禁止粘贴】限制,支持【免费OCR识别】 // @author 诸葛 // @license MIT // @match *://*/* // @run-at document-start // @grant none // @namespace https://greasyfork.org/users/1271291 // ==/UserScript== (function() { 'use strict'; /***************************************************************************** * 0. 配置与全局变量 *****************************************************************************/ const DISABLED_EVENTS = [ 'contextmenu', 'selectstart', 'copy', 'cut', 'paste', 'keydown', 'keypress', 'keyup', 'mousedown', 'mouseup' ]; const OCR_BUTTON_HIDE_KEY = 'ocrButtonHidePermanently'; const UNLOCK_ENABLED_KEY = 'unlockFeatureEnabled'; // 是否启用解锁的标记 // OCR按钮 & 弹窗引用 let ocrBtn = null; let popup = null; // 用于捕获阶段事件移除 const captureHandlers = {}; // 在脚本开始时,先读取标记,决定是否启用解锁 let isEnabled = (localStorage.getItem(UNLOCK_ENABLED_KEY) === 'true'); /***************************************************************************** * 1. 如果标记已开启,则立即拦截事件 *****************************************************************************/ if (isEnabled) { // 在最早(document-start)阶段拦截,效果最好 enableUnlockCore(); } /** * 核心启用函数:真正拦截事件 * 只在 document-start 阶段执行才能 100% 覆盖网站脚本 */ function enableUnlockCore() { const originalAdd = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function(type, listener, options) { if (DISABLED_EVENTS.includes(type)) { return; // 拦截 } return originalAdd.call(this, type, listener, options); }; const originalRemove = EventTarget.prototype.removeEventListener; EventTarget.prototype.removeEventListener = function(type, listener, options) { return originalRemove.call(this, type, listener, options); }; // 清空 document/window 上的 onXXX 事件 DISABLED_EVENTS.forEach(evt => { document['on' + evt] = null; window['on' + evt] = null; }); // 在捕获阶段阻断各类事件 DISABLED_EVENTS.forEach(evt => { const handler = function(e) { e.stopPropagation(); e.stopImmediatePropagation(); }; captureHandlers[evt] = handler; document.addEventListener(evt, handler, true); }); console.log('【解锁功能】已在 document-start 阶段启用'); } /** * 关闭核心功能 * 仅在刷新页面后才会彻底复原到未启用状态 */ function disableUnlockCore() { // 尝试移除捕获阶段监听器 Object.keys(captureHandlers).forEach(evt => { const handler = captureHandlers[evt]; document.removeEventListener(evt, handler, true); }); console.log('【解锁功能】已关闭核心逻辑(下次刷新生效)'); } /***************************************************************************** * 2. DOM 加载完成后,插入控制按钮 & OCR按钮(若已启用) *****************************************************************************/ function onDOMReady() { createControlButtons(); // 如果功能已启用,并且OCR没有被永久关闭,则显示OCR按钮 if (isEnabled && localStorage.getItem(OCR_BUTTON_HIDE_KEY) !== 'true') { createOcrButton(); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', onDOMReady); } else { onDOMReady(); } /***************************************************************************** * 3. “启用/关闭”控制按钮 & 刷新流程 *****************************************************************************/ function createControlButtons() { const container = document.createElement('div'); container.style.position = 'fixed'; container.style.left = '20px'; container.style.top = '50%'; container.style.transform = 'translateY(-50%)'; container.style.zIndex = 999998; container.style.display = 'flex'; container.style.flexDirection = 'column'; container.style.gap = '10px'; if (!isEnabled) { // 若当前为关闭状态,显示“启用功能”按钮 const enableBtn = document.createElement('button'); enableBtn.textContent = '启用功能'; styleButton(enableBtn, '#17a2b8'); // 蓝绿色 enableBtn.addEventListener('click', () => { if (isEnabled) { showMessage('功能已是开启状态,无需重复开启'); return; } localStorage.setItem(UNLOCK_ENABLED_KEY, 'true'); showMessage('功能已启用,页面将刷新以生效', 2000); setTimeout(() => { location.reload(); }, 2000); }); container.appendChild(enableBtn); } else { // 若当前为启用状态,显示“关闭功能”按钮 const disableBtn = document.createElement('button'); disableBtn.textContent = '关闭功能'; styleButton(disableBtn, '#6c757d'); // 灰色 disableBtn.addEventListener('click', () => { if (!isEnabled) { showMessage('功能已是关闭状态,无需重复关闭'); return; } localStorage.setItem(UNLOCK_ENABLED_KEY, 'false'); showMessage('功能已关闭,页面将刷新以生效', 2000); // 先局部disable disableUnlockCore(); setTimeout(() => { location.reload(); }, 2000); }); container.appendChild(disableBtn); } document.body.appendChild(container); } // 给按钮统一加点样式 function styleButton(btn, bgColor) { btn.style.padding = '10px 16px'; btn.style.borderRadius = '6px'; btn.style.border = 'none'; btn.style.backgroundColor = bgColor; btn.style.color = '#fff'; btn.style.cursor = 'pointer'; btn.style.fontSize = '14px'; btn.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)'; } /***************************************************************************** * 4. 文字助手按钮 & 弹窗 *****************************************************************************/ function createOcrButton() { if (ocrBtn) return; ocrBtn = document.createElement('button'); ocrBtn.textContent = '文字助手'; styleButton(ocrBtn, '#28a745'); // 绿色 ocrBtn.style.position = 'fixed'; ocrBtn.style.left = '20px'; ocrBtn.style.top = '50%'; ocrBtn.style.transform = 'translateY(-50%)'; ocrBtn.style.zIndex = 999999; ocrBtn.style.marginTop = '80px'; // 与控制按钮错开一点 ocrBtn.addEventListener('click', showOcrPopup); document.body.appendChild(ocrBtn); } function removeOcrButton() { if (ocrBtn) { ocrBtn.remove(); ocrBtn = null; } closePopup(); } function showOcrPopup() { if (popup) { popup.style.display = 'block'; return; } const overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.style.top = 0; overlay.style.left = 0; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0,0,0,0.3)'; overlay.style.zIndex = 1000000; popup = document.createElement('div'); popup.style.position = 'fixed'; popup.style.left = '50%'; popup.style.top = '50%'; popup.style.transform = 'translate(-50%, -50%)'; popup.style.width = '320px'; popup.style.backgroundColor = '#fff'; popup.style.borderRadius = '8px'; popup.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)'; popup.style.padding = '20px'; popup.style.textAlign = 'center'; const text = document.createElement('p'); text.textContent = '文字助手暂未完全开发,这里提供免费OCR链接供使用。'; text.style.margin = '0 0 20px 0'; popup.appendChild(text); const btnContainer = document.createElement('div'); btnContainer.style.display = 'flex'; btnContainer.style.justifyContent = 'space-between'; btnContainer.style.gap = '10px'; // 使用助手 const useBtn = document.createElement('button'); useBtn.textContent = '使用助手'; styleButton(useBtn, '#007bff'); useBtn.style.flex = '1'; useBtn.addEventListener('click', () => { window.open('https://hiroi-sora.lanzoul.com/s/umi-ocr', '_blank'); closePopup(); }); btnContainer.appendChild(useBtn); // 本次关闭 const closeOnceBtn = document.createElement('button'); closeOnceBtn.textContent = '本次关闭'; styleButton(closeOnceBtn, '#6c757d'); closeOnceBtn.style.flex = '1'; closeOnceBtn.addEventListener('click', () => { removeOcrButton(); closePopup(); }); btnContainer.appendChild(closeOnceBtn); // 永久关闭 const closeForeverBtn = document.createElement('button'); closeForeverBtn.textContent = '永久关闭'; styleButton(closeForeverBtn, '#dc3545'); closeForeverBtn.style.flex = '1'; closeForeverBtn.addEventListener('click', () => { localStorage.setItem(OCR_BUTTON_HIDE_KEY, 'true'); removeOcrButton(); closePopup(); }); btnContainer.appendChild(closeForeverBtn); popup.appendChild(btnContainer); overlay.appendChild(popup); document.body.appendChild(overlay); } function closePopup() { if (popup) { popup.remove(); popup = null; } const overlay = document.querySelector('div[style*="background-color: rgba(0,0,0,0.3)"]'); if (overlay) overlay.remove(); } /***************************************************************************** * 5. 全局提示函数 (默认3秒自动消失) *****************************************************************************/ function showMessage(msg, duration = 3000) { const overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.style.top = 0; overlay.style.left = 0; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0,0,0,0.2)'; overlay.style.zIndex = 1000002; const box = document.createElement('div'); box.style.position = 'fixed'; box.style.left = '50%'; box.style.top = '50%'; box.style.transform = 'translate(-50%, -50%)'; box.style.minWidth = '200px'; box.style.backgroundColor = '#fff'; box.style.borderRadius = '8px'; box.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)'; box.style.padding = '16px'; box.style.textAlign = 'center'; const p = document.createElement('p'); p.textContent = msg; p.style.margin = '0 0 12px 0'; box.appendChild(p); const closeBtn = document.createElement('button'); closeBtn.textContent = '关闭'; styleButton(closeBtn, '#007bff'); closeBtn.style.padding = '5px 10px'; closeBtn.addEventListener('click', () => { overlay.remove(); }); box.appendChild(closeBtn); overlay.appendChild(box); document.body.appendChild(overlay); setTimeout(() => { if (overlay.parentNode) { overlay.remove(); } }, duration); } })();