复制粘贴解锁器

破除网页禁止复制粘贴的限制,特别优化学习通平台

// ==UserScript==
// @name         复制粘贴解锁器
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  破除网页禁止复制粘贴的限制,特别优化学习通平台
// @author       pan
// @match        *://*/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    
    // 移除禁止复制粘贴的事件监听器
    function removeEventListeners() {
      const events = ['copy', 'cut', 'paste', 'select', 'selectstart', 'contextmenu', 'dragstart', 'mousedown', 'mouseup', 'keydown', 'keyup'];
      
      // 移除document上的事件限制
      events.forEach(event => {
        document.addEventListener(event, function(e) {
          e.stopImmediatePropagation();
          return true;
        }, true);
        
        // 尝试直接覆盖原生onxxx属性
        Object.defineProperty(document, 'on' + event, {
          get: function() { return null; },
          set: function() { return true; },
          configurable: true
        });
        
        // 尝试覆盖window上的事件
        Object.defineProperty(window, 'on' + event, {
          get: function() { return null; },
          set: function() { return true; },
          configurable: true
        });
      });
      
      // 使用MutationObserver监听DOM变化,确保对新添加的元素也生效
      const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
          if (mutation.addedNodes) {
            mutation.addedNodes.forEach(function(node) {
              if (node.nodeType === 1) { // 元素节点
                enableCopyPaste(node);
              }
            });
          }
        });
      });
      
      observer.observe(document.body, {
        childList: true,
        subtree: true
      });
    }
    
    // 对指定元素及其子元素启用复制粘贴
    function enableCopyPaste(element) {
      if (!element) return;
      
      // 尝试移除可能禁止复制的CSS属性
      const overrideStyles = {
        'user-select': 'auto !important',
        '-webkit-user-select': 'auto !important',
        '-moz-user-select': 'auto !important',
        '-ms-user-select': 'auto !important',
        'pointer-events': 'auto !important'
      };
      
      Object.keys(overrideStyles).forEach(property => {
        element.style.setProperty(property, overrideStyles[property], 'important');
      });
      
      // 防止默认的事件处理程序干扰复制粘贴
      const events = ['copy', 'cut', 'paste', 'select', 'selectstart', 'contextmenu', 'dragstart', 'mousedown', 'mouseup', 'keydown', 'keyup'];
      events.forEach(event => {
        element.addEventListener(event, function(e) {
          e.stopImmediatePropagation();
          return true;
        }, true);
        
        // 移除元素上的事件处理函数
        element['on' + event] = null;
      });
      
      // 移除可能的复制粘贴限制属性
      element.removeAttribute('unselectable');
      element.removeAttribute('oncontextmenu');
      element.removeAttribute('oncopy');
      element.removeAttribute('oncut');
      element.removeAttribute('onpaste');
      element.removeAttribute('onselectstart');
      element.removeAttribute('onmousedown');
      element.removeAttribute('onkeydown');
      
      // 递归处理子元素
      if (element.children && element.children.length > 0) {
        Array.from(element.children).forEach(child => {
          enableCopyPaste(child);
        });
      }
    }
    
    // 专门处理学习通网站
    function handleChaoxing() {
      if (window.location.href.includes('chaoxing.com') || 
          window.location.href.includes('edu.cn') ||
          document.domain.includes('chaoxing') ||
          document.domain.includes('xueyitong') ||
          document.domain.includes('xuexitong')) {
        
        console.log('检测到学习通网站,应用特殊处理...');
        
        // 覆盖学习通特有的禁用复制粘贴的方法
        try {
          // 尝试覆盖学习通的禁止复制粘贴函数
          if (typeof window.forbidBackSpace === 'function') {
            window.forbidBackSpace = function() { return true; };
          }
          
          // 覆盖可能存在的学习通专有方法
          window.checkRight = function() { return true; };
          window.canCopy = function() { return true; };
          window.oncontextmenu = function() { return true; };
          
          // 覆盖更多可能存在的函数
          if (typeof window.removeSelect === 'function') {
            window.removeSelect = function() { return true; };
          }
          
          // 特别处理视频播放器内的限制
          if (typeof window.AntiCopy === 'function' || typeof window.AntiCopy === 'object') {
            window.AntiCopy = function() { return true; };
          }
        } catch (e) {
          console.log('尝试覆盖学习通方法时出错:', e);
        }
        
        // 针对iframe处理
        function handleIframes() {
          const iframes = document.querySelectorAll('iframe');
          iframes.forEach(iframe => {
            try {
              if (iframe.contentDocument) {
                enableCopyPaste(iframe.contentDocument.body);
              }
            } catch (e) {
              // 跨域iframe会导致安全错误,忽略
            }
          });
        }
        
        // 立即处理iframe
        handleIframes();
        
        // 每秒检查一次iframe,因为学习通常常动态加载iframe
        setInterval(handleIframes, 1000);
        
        // 学习通在内容加载后可能会重新应用禁止复制,需要延迟处理
        setTimeout(function() {
          enableCopyPaste(document.body);
          console.log('针对学习通的延迟处理已执行');
        }, 3000);
        
        // 检测页面URL变化
        let lastUrl = location.href;
        const bodyObserver = new MutationObserver(() => {
          if (lastUrl !== location.href) {
            lastUrl = location.href;
            console.log("学习通页面URL变化,重新应用解锁...");
            setTimeout(() => {
              enableCopyPaste(document.body);
              handleIframes();
            }, 500);
          }
        });
        
        bodyObserver.observe(document.body, {
          childList: true,
          subtree: true
        });
        
        // 处理学习通常见的文本选择区域
        const selectionAreas = document.querySelectorAll('.ans-reading, .ans-job-finished, .ans-attach-ct, .textHTML, .ans-cc');
        selectionAreas.forEach(area => {
          if (area) {
            enableCopyPaste(area);
          }
        });
      }
    }
    
    // 页面加载完成后执行
    function init() {
      console.log('复制粘贴解锁器初始化...');
      removeEventListeners();
      enableCopyPaste(document.body);
      handleChaoxing();
      
      // 创建提示消息
      const notification = document.createElement('div');
      notification.textContent = '复制粘贴限制已解除';
      notification.style.position = 'fixed';
      notification.style.bottom = '20px';
      notification.style.right = '20px';
      notification.style.padding = '10px 15px';
      notification.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
      notification.style.color = 'white';
      notification.style.borderRadius = '4px';
      notification.style.zIndex = '9999';
      notification.style.opacity = '1';
      notification.style.transition = 'opacity 0.5s';
      
      document.body.appendChild(notification);
      
      // 2秒后隐藏提示
      setTimeout(() => {
        notification.style.opacity = '0';
        setTimeout(() => {
          if (notification.parentNode) {
            notification.parentNode.removeChild(notification);
          }
        }, 500);
      }, 2000);
      
      // 监听粘贴事件,辅助处理一些特殊情况
      document.addEventListener('paste', function(e) {
        // 确保粘贴事件能够正常进行
        if (e.isTrusted) {
          // 不做任何阻止
        }
      }, true);
      
      // 周期性重新应用解锁,以防网站在加载后动态应用限制
      setInterval(function() {
        enableCopyPaste(document.body);
        handleChaoxing();
      }, 5000);
      
      // 监听页面可见性变化,当页面从隐藏变为可见时重新应用解锁(例如从其他标签页切回)
      document.addEventListener('visibilitychange', function() {
        if (document.visibilityState === 'visible') {
          console.log('页面可见性变化,重新应用解锁...');
          enableCopyPaste(document.body);
          handleChaoxing();
        }
      });
      
      // 劫持history API以检测页面导航
      const originalPushState = history.pushState;
      const originalReplaceState = history.replaceState;
      
      history.pushState = function() {
        originalPushState.apply(this, arguments);
        console.log('检测到pushState导航,重新应用解锁...');
        setTimeout(() => {
          enableCopyPaste(document.body);
          handleChaoxing();
        }, 500);
      };
      
      history.replaceState = function() {
        originalReplaceState.apply(this, arguments);
        console.log('检测到replaceState导航,重新应用解锁...');
        setTimeout(() => {
          enableCopyPaste(document.body);
          handleChaoxing();
        }, 500);
      };
      
      // 监听hashchange事件(URL的锚点变化)
      window.addEventListener('hashchange', function() {
        console.log('URL锚点变化,重新应用解锁...');
        setTimeout(() => {
          enableCopyPaste(document.body);
          handleChaoxing();
        }, 500);
      });
      
      // 监听所有点击事件,处理可能导致页面内容变化的操作
      document.addEventListener('click', function(e) {
        // 检测是否点击了学习通常见的导航元素
        if (e.target && (
            e.target.classList.contains('navItem') || 
            e.target.classList.contains('ans-job-icon') || 
            e.target.parentElement?.classList.contains('navItem') ||
            e.target.tagName === 'A' || 
            e.target.closest('a')
        )) {
          console.log('检测到潜在的页面导航点击,将在延迟后重新应用解锁...');
          setTimeout(() => {
            enableCopyPaste(document.body);
            handleChaoxing();
          }, 1000);
        }
      }, true);
    }
    
    // 当DOM加载完成时执行初始化
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', init);
    } else {
      init();
    }
    
    // 在页面加载完成时再次执行,确保覆盖所有内容
    window.addEventListener('load', function() {
      console.log('页面完全加载,再次应用解锁...');
      enableCopyPaste(document.body);
      handleChaoxing();
    });
    
    // 重写可能被网站覆盖的原生函数
    // 这是处理复制粘贴限制的核心方法
    const originalDescriptors = {};
    
    // 保存原始方法,以便后续可能的恢复
    ['copy', 'cut', 'paste', 'contextmenu', 'selectstart'].forEach(function(event) {
      originalDescriptors['on' + event] = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'on' + event);
    });
    
    // 覆盖Document原型上的方法
    ['oncontextmenu', 'oncopy', 'oncut', 'onpaste', 'onselectstart', 'onmousedown', 'onkeydown', 'onkeyup'].forEach(function(prop) {
      Object.defineProperty(Document.prototype, prop, {
        get: function() {
          return function() { return true; };
        },
        set: function() {
          return true;
        },
        configurable: true
      });
    });
    
    // 覆盖HTMLElement原型上的方法
    ['oncontextmenu', 'oncopy', 'oncut', 'onpaste', 'onselectstart', 'onmousedown', 'onkeydown', 'onkeyup'].forEach(function(prop) {
      Object.defineProperty(HTMLElement.prototype, prop, {
        get: function() {
          return function() { return true; };
        },
        set: function() {
          return true;
        },
        configurable: true
      });
    });
    
    // 特别处理学习通的函数
    // 覆盖或禁用学习通常用来阻止复制粘贴的函数
    const knownFunctions = [
      'forbidBackSpace',
      'checkRight',
      'canCopy',
      'disableCopy',
      'disablePaste',
      'disableSelect',
      'disableContextMenu',
      'removeSelect',
      'disablePrint',
      'disableSave',
      'disableViewSource',
      'oncontextmenu',
      'preventDefault',
      'AntiCopy'
    ];
    
    knownFunctions.forEach(function(funcName) {
      try {
        if (typeof window[funcName] === 'function') {
          window[funcName] = function() { return true; };
        }
      } catch (e) {}
    });
    
    // 尝试破解动态添加的事件监听器
    const originalAddEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      if (['copy', 'paste', 'cut', 'contextmenu', 'selectstart', 'mousedown', 'keydown'].includes(type)) {
        // 不添加这些可能会限制复制粘贴的事件
        console.log('阻止添加事件: ' + type);
        return;
      }
      return originalAddEventListener.call(this, type, listener, options);
    };
    
    // 覆盖 document.oncontextmenu = null 这种直接赋值
    Object.defineProperty(document, 'oncontextmenu', {
      get: function() { return function() { return true; }; },
      set: function() { return true; }
    });
    
    // 处理在控制台中手动设置的 JS 限制
    setInterval(function() {
      try {
        document.oncontextmenu = function() { return true; };
        document.oncopy = function() { return true; };
        document.onpaste = function() { return true; };
        document.onselectstart = function() { return true; };
        document.ondragstart = function() { return true; };
        document.onmousedown = function() { return true; };
      } catch (e) {}
    }, 2000);
})(); 

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址