为什么不让我复制?

恢复被网站禁用的复制功能,例如飞书、钉钉、百度文库等。支持ctrl+c、command+c复制。注意默认不启动,且只能解锁纯文本,解锁后仍然会出现弹窗,但可以正常复制内容。使用时请遵守相关法律法规及网站规定,尊重版权和知识产权。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         为什么不让我复制?
// @namespace    http://tampermonkey.net/
// @version      2.3.1
// @description  恢复被网站禁用的复制功能,例如飞书、钉钉、百度文库等。支持ctrl+c、command+c复制。注意默认不启动,且只能解锁纯文本,解锁后仍然会出现弹窗,但可以正常复制内容。使用时请遵守相关法律法规及网站规定,尊重版权和知识产权。
// @author       HuSheng
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @run-at       document-start
// @license      GPL-2.0-only
// ==/UserScript==

(function () {
    'use strict';

    // 文本可选中
    const style = document.createElement('style');
    style.textContent = `
        * {
            user-select: text !important;
            -webkit-user-select: text !important;
        }
    `;
    document.documentElement.appendChild(style);

    const original = {
        addEventListener: EventTarget.prototype.addEventListener,
        preventDefault: Event.prototype.preventDefault,
        stopPropagation: Event.prototype.stopPropagation,
        stopImmediatePropagation: Event.prototype.stopImmediatePropagation
    };

    let enabled = false;

    // 注册菜单命令
    GM_registerMenuCommand("启用/关闭 (默认为关闭)", function () {
        enabled = !enabled;
        if (enabled) {
            overrideEvents();
        } else {
            restoreEvents();
        }
        updateTitle();
    });

    function updateTitle() {
        if (!document.title) return;
        const prefix = '(✅已解锁) ';
        if (enabled) {
            if (!document.title.startsWith(prefix)) {
                document.title = prefix + document.title.replace(/^(✅已解锁)\s*/, '');
            }
        } else {
            document.title = document.title.replace(/^(✅已解锁)\s*/, '');
        }
    }

    const titleObserver = new MutationObserver(() => {
        if (enabled) {
            updateTitle();
        }
    });
    titleObserver.observe(document.querySelector('title') || document.head, {
        subtree: true,
        characterData: true,
        childList: true
    });

    // 覆盖事件
    function overrideEvents() {
        EventTarget.prototype.addEventListener = function (type, listener, options) {
            if (type === 'copy') {
                return;
            }

            if (type === 'keydown') {
                const listenerStr = listener.toString();
                if (listenerStr.includes('keyCode:67') ||
                    listenerStr.includes('keyCode===67') ||
                    listenerStr.includes('key:"c"') ||
                    (listenerStr.includes('ctrlKey') && listenerStr.includes('67')) ||
                    (listenerStr.includes('metaKey') && listenerStr.includes('67'))) {
                    return;
                }
            }
            original.addEventListener.call(this, type, listener, options);
        };

        Event.prototype.preventDefault = function () {
            if (this.type === 'copy' || (this.type === 'keydown' && this.keyCode === 67 && (this.ctrlKey || this.metaKey))) {
                return;
            }
            original.preventDefault.call(this);
        };

        Event.prototype.stopPropagation = function () {
            if (this.type === 'copy' || (this.type === 'keydown' && this.keyCode === 67 && (this.ctrlKey || this.metaKey))) {
                return;
            }
            original.stopPropagation.call(this);
        };

        Event.prototype.stopImmediatePropagation = function () {
            if (this.type === 'copy' || (this.type === 'keydown' && this.keyCode === 67 && (this.ctrlKey || this.metaKey))) {
                return;
            }
            original.stopImmediatePropagation.call(this);
        };
    }

    // 还原事件
    function restoreEvents() {
        EventTarget.prototype.addEventListener = original.addEventListener;
        Event.prototype.preventDefault = original.preventDefault;
        Event.prototype.stopPropagation = original.stopPropagation;
        Event.prototype.stopImmediatePropagation = original.stopImmediatePropagation;
    }

    const savedListeners = [];

})();