Greasy Fork

Greasy Fork is available in English.

网页复制限制解除

解除网站复制限制、去除复制水印

当前为 2024-10-31 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网页复制限制解除
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  解除网站复制限制、去除复制水印
// @author       Heavrnl
// @license      MIT
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    // 检查是否在 iframe 中
    const isInIframe = window !== window.top;

    // 添加设置界面的样式
    GM_addStyle(`
        .watermark-settings {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0,0,0,0.3);
            z-index: 10000;
            width: 500px;
            font-family: Arial, sans-serif;
        }
        .watermark-settings h2 {
            margin: 0 0 15px 0;
            color: #333;
        }
        .watermark-settings .buttons {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
        }
        .watermark-settings button {
            padding: 8px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        .watermark-settings .save {
            background: #28a745;
            color: white;
        }
        .watermark-settings .cancel {
            background: #dc3545;
            color: white;
        }
        .watermark-settings .overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.5);
            z-index: 9999;
        }
    `);

    // 初始化设置 - 只在主页面中执行
    if (!isInIframe) {
        if (GM_getValue('watermarkSites') === undefined) {
            GM_setValue('watermarkSites', {});  // 使用对象存储各网站的去水印状态
        }
        if (GM_getValue('copySites') === undefined) {
            GM_setValue('copySites', {});  // 使用对象存储各网站的复制解除状态
        }
    }

    // 检查当前网站的复制解除状态
    const isCopyEnabled = () => {
        const currentHost = window.location.hostname;
        const copySites = GM_getValue('copySites', {});
        return copySites[currentHost] || false;
    };

    // 修改去水印功能
    function removeWatermark() {
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});

        if (!watermarkSites[currentHost]) return;

        document.addEventListener('copy', function(e) {
            e.stopPropagation();
            const selection = window.getSelection();
            e.clipboardData.setData('text/plain', selection.toString());
            e.preventDefault();
        }, true);
    }

    // 创建并添加按钮
    const button = document.createElement("button");
    // 使用 SVG 图标替代文字
    const svgIcon = `
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path>
            <rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect>
        </svg>`;

    button.innerHTML = svgIcon;

    // 根据存储的状态设置按钮样式
    const isEnabled = GM_getValue('enableCopyRemoval', false);
    const getButtonStyle = (enabled) => `
        position: fixed;
        right: 10px;
        bottom: 15%;
        z-index: 9999;
        width: 32px;
        height: 32px;
        padding: 6px;
        background-color: ${enabled ? 'rgba(220, 53, 69, 0.3)' : 'rgba(40, 167, 69, 0.3)'};
        color: white;
        border: none;
        border-radius: 50%;
        cursor: pointer;
        transition: all 0.3s ease;
        display: flex;
        align-items: center;
        justify-content: center;
        opacity: 0.3;
    `;

    button.style.cssText = getButtonStyle(isEnabled);

    // 悬停效果
    button.onmouseenter = () => {
        button.style.opacity = "1";
        const currentHost = window.location.hostname;
        const copySites = GM_getValue('copySites', {});
        const isEnabled = copySites[currentHost] || false;
        button.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.9)' :
            'rgba(40, 167, 69, 0.9)';
    };

    button.onmouseleave = () => {
        button.style.opacity = "0.3";
        const currentHost = window.location.hostname;
        const copySites = GM_getValue('copySites', {});
        const isEnabled = copySites[currentHost] || false;
        button.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.3)' :
            'rgba(40, 167, 69, 0.3)';
    };

    document.body.appendChild(button);

    // 修改点击按钮时切换状态的代码
    const handleButtonClick = () => {
        const currentHost = window.location.hostname;
        const copySites = GM_getValue('copySites', {});
        const currentState = copySites[currentHost] || false;

        if (!currentState) {
            // 启用当前网站的复制解除
            copySites[currentHost] = true;
            GM_setValue('copySites', copySites);
            // 立即启用复制解除
            enableCopyAndRemoveOverlay();
            // 更新按钮样式
            button.style.backgroundColor = 'rgba(220, 53, 69, 0.3)';

            // 立即应用额外的复制解除措施
            const style = document.createElement('style');
            style.innerHTML = `
                * {
                    -webkit-user-select: text !important;
                    -moz-user-select: text !important;
                    -ms-user-select: text !important;
                    user-select: text !important;
                    -webkit-touch-callout: default !important;
                }
                ::selection {
                    background-color: #338FFF !important;
                    color: #fff !important;
                }
            `;
            document.head.appendChild(style);

            // 立即移除所有元素的复制限制
            document.querySelectorAll('*').forEach(element => {
                element.style.userSelect = "text";
                element.style.webkitUserSelect = "text";
                element.style.msUserSelect = "text";
                element.style.MozUserSelect = "text";

                // 移除事件监听器
                element.oncontextmenu = null;
                element.onselectstart = null;
                element.onselect = null;
                element.oncopy = null;
                element.onbeforecopy = null;
                element.oncut = null;
                element.onpaste = null;
                element.ondrag = null;
                element.ondragstart = null;
            });

            // 立即覆盖文档级别的事件
            document.oncontextmenu = null;
            document.onselectstart = null;
            document.oncopy = null;
            document.oncut = null;
            document.onpaste = null;

            // 添加复制事件监听器
            document.addEventListener('copy', function(e) {
                e.stopPropagation();
                const selection = window.getSelection();
                e.clipboardData.setData('text/plain', selection.toString());
            }, true);

        } else {
            // 禁用当前网站的复制解除
            copySites[currentHost] = false;
            GM_setValue('copySites', copySites);
            location.reload(); // 刷新页面以恢复原始状态
        }
    };

    // 绑定点击事件
    button.addEventListener("click", handleButtonClick);

    // 移除复制限制及遮挡层的功能
    const enableCopyAndRemoveOverlay = () => {
        const currentHost = window.location.hostname;
        const copySites = GM_getValue('copySites', {});

        if (!copySites[currentHost]) return;

        // 处理CSDN特定的复制限制
        document.querySelectorAll('*').forEach(element => {
            // 移除CSDN特定的user-select限制
            if (element.classList.contains('htmledit_views') ||
                element.classList.contains('markdown_views') ||
                element.classList.contains('article_content')) {
                element.style.cssText = `
                    -webkit-user-select: text !important;
                    -moz-user-select: text !important;
                    -ms-user-select: text !important;
                    user-select: text !important;
                `;
            }

            // 移除CSDN的事件监听器
            element.oncontextmenu = null;
            element.onselectstart = null;
            element.onselect = null;
            element.oncopy = null;
            element.onbeforecopy = null;
            element.oncut = null;
            element.onpaste = null;
            element.ondrag = null;
            element.ondragstart = null;
        });

        // 覆盖CSDN的复制事件处理
        document.addEventListener('copy', function(e) {
            e.stopPropagation();
            const selection = window.getSelection();
            e.clipboardData.setData('text/plain', selection.toString());
        }, true);

        // 移除CSDN的遮罩层和弹窗
        const removeOverlays = () => {
            const overlays = document.querySelectorAll('.login-mark, .login-box');
            overlays.forEach(overlay => overlay.remove());
        };

        // 定期检查并移除遮罩
        setInterval(removeOverlays, 100);

        // 移除所有元素的复制限制
        document.querySelectorAll('*').forEach(element => {
            // 允许选择文本
            element.style.userSelect = "text";
            element.style.webkitUserSelect = "text";
            element.style.msUserSelect = "text";
            element.style.MozUserSelect = "text";

            // 移除事件监听器
            element.onselectstart = null;
            element.oncontextmenu = null;
            element.onmousedown = null;
            element.onkeydown = null;
            element.oncopy = null;
            element.oncut = null;
            element.ondrag = null;
            element.ondragstart = null;

            // 移除 unselectable 属性
            element.removeAttribute('unselectable');
            element.removeAttribute('oncontextmenu');
            element.removeAttribute('oncopy');
            element.removeAttribute('oncut');
            element.removeAttribute('onselectstart');
        });

        // 移除遮挡层
        document.querySelectorAll('*').forEach(element => {
            const style = window.getComputedStyle(element);
            if ((style.position === 'absolute' || style.position === 'fixed') &&
                (style.opacity === '0' || parseFloat(style.opacity) < 0.1) &&
                style.zIndex > 0) {
                element.remove();
            }
        });

        // 覆盖常见的禁用右键和复制的方法
        document.oncontextmenu = null;
        document.onselectstart = null;
        document.oncopy = null;
        document.oncut = null;
        document.onpaste = null;
        document.onkeydown = null;
        document.onmousedown = null;

        // 覆盖 window 对象上的限制方法
        window.oncontextmenu = null;
        window.onselectstart = null;
        window.oncopy = null;
        window.oncut = null;
        window.onpaste = null;
        window.onkeydown = null;
        window.onmousedown = null;

        // 阻止页面使用 addEventListener 添加新的限制
        const originalAddEventListener = EventTarget.prototype.addEventListener;
        EventTarget.prototype.addEventListener = function(type, listener, options) {
            if (type === 'contextmenu' || type === 'selectstart' ||
                type === 'copy' || type === 'cut' || type === 'paste' ||
                type === 'keydown' || type === 'mousedown') {
                return;
            }
            originalAddEventListener.call(this, type, listener, options);
        };

        // 移除 CSS 限制
        const style = document.createElement('style');
        style.innerHTML = `
            * {
                -webkit-user-select: text !important;
                -moz-user-select: text !important;
                -ms-user-select: text !important;
                user-select: text !important;
                -webkit-touch-callout: default !important;
            }
            ::selection {
                background-color: #338FFF !important;
                color: #fff !important;
            }
        `;
        document.head.appendChild(style);
    };

    // 修改 MutationObserver,只在功能开启时才观察
    const observer = new MutationObserver(() => {
        if (GM_getValue('enableCopyRemoval', false)) {
            enableCopyAndRemoveOverlay();
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });

    // 创建并添加去水印按钮
    const watermarkButton = document.createElement("button");
    const watermarkSvgIcon = `
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <line x1="1" y1="1" x2="23" y2="23"></line>
            <path d="M21 21H3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h18a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2z"></path>
        </svg>`;

    watermarkButton.innerHTML = watermarkSvgIcon;

    // 获取去水印功能的状态
    const isWatermarkEnabled = () => {
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});
        return watermarkSites[currentHost] || false;
    };

    // 设置去水印按钮样式
    const getWatermarkButtonStyle = (enabled) => `
        position: fixed;
        right: 10px;
        bottom: 10%;
        z-index: 9999;
        width: 32px;
        height: 32px;
        padding: 6px;
        background-color: ${enabled ? 'rgba(220, 53, 69, 0.3)' : 'rgba(40, 167, 69, 0.3)'};
        color: white;
        border: none;
        border-radius: 50%;
        cursor: pointer;
        transition: all 0.3s ease;
        display: flex;
        align-items: center;
        justify-content: center;
        opacity: 0.3;
    `;

    watermarkButton.style.cssText = getWatermarkButtonStyle(isWatermarkEnabled());

    // 去水印按钮的悬停效果
    watermarkButton.onmouseenter = () => {
        watermarkButton.style.opacity = "1";
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});
        const isEnabled = watermarkSites[currentHost] || false;
        watermarkButton.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.9)' :
            'rgba(40, 167, 69, 0.9)';
    };

    watermarkButton.onmouseleave = () => {
        watermarkButton.style.opacity = "0.3";
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});
        const isEnabled = watermarkSites[currentHost] || false;
        watermarkButton.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.3)' :
            'rgba(40, 167, 69, 0.3)';
    };

    // 去水印按钮点击事件
    watermarkButton.addEventListener("click", () => {
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});
        const currentState = watermarkSites[currentHost] || false;

        watermarkSites[currentHost] = !currentState;
        GM_setValue('watermarkSites', watermarkSites);

        // 立即应用新状态
        if (!currentState) {
            removeWatermark();
        } else {
            location.reload(); // 如果是关闭状态,需要刷新页面
        }

        // 更新按钮样式
        watermarkButton.style.cssText = getWatermarkButtonStyle(!currentState);
    });

    document.body.appendChild(watermarkButton);

    // 添加按钮组样式
    GM_addStyle(`
        .float-button-group {
            position: fixed;
            right: 10px;
            bottom: 15%;
            z-index: 9999;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .float-button {
            width: 32px;
            height: 32px;
            padding: 6px;
            background-color: rgba(40, 167, 69, 0.3);
            color: white;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0.3;
        }
    `);

    // 创建按钮组容器
    const buttonGroup = document.createElement('div');
    buttonGroup.className = 'float-button-group';

    // 创建复制解除按钮
    const copyButton = document.createElement("button");
    copyButton.className = 'float-button';
    copyButton.innerHTML = svgIcon;

    // 创建去水印按钮
    const watermarkBtn = document.createElement("button");
    watermarkBtn.className = 'float-button';
    watermarkBtn.innerHTML = watermarkSvgIcon;

    // 更新按钮状态的函数
    const updateButtonStyle = (btn, enabled) => {
        btn.style.backgroundColor = enabled ?
            'rgba(220, 53, 69, 0.3)' :
            'rgba(40, 167, 69, 0.3)';
    };

    // 设置初始状态
    const copyEnabled = isCopyEnabled();
    updateButtonStyle(copyButton, copyEnabled);

    const watermarkEnabled = isWatermarkEnabled();
    updateButtonStyle(watermarkBtn, watermarkEnabled);

    // 复制按钮的悬停效果
    copyButton.onmouseenter = () => {
        copyButton.style.opacity = "1";
        const isEnabled = isCopyEnabled();
        copyButton.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.9)' :
            'rgba(40, 167, 69, 0.9)';
    };

    copyButton.onmouseleave = () => {
        copyButton.style.opacity = "0.3";
        const isEnabled = isCopyEnabled();
        copyButton.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.3)' :
            'rgba(40, 167, 69, 0.3)';
    };

    // 去水印按钮的悬停效果
    watermarkBtn.onmouseenter = () => {
        watermarkBtn.style.opacity = "1";
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});
        const isEnabled = watermarkSites[currentHost] || false;
        watermarkBtn.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.9)' :
            'rgba(40, 167, 69, 0.9)';
    };

    watermarkBtn.onmouseleave = () => {
        watermarkBtn.style.opacity = "0.3";
        const currentHost = window.location.hostname;
        const watermarkSites = GM_getValue('watermarkSites', {});
        const isEnabled = watermarkSites[currentHost] || false;
        watermarkBtn.style.backgroundColor = isEnabled ?
            'rgba(220, 53, 69, 0.3)' :
            'rgba(40, 167, 69, 0.3)';
    };

    // 绑定点击事件
    copyButton.addEventListener("click", handleButtonClick);
    watermarkBtn.addEventListener("click", handleWatermarkButtonClick);

    // 将按钮添加到按钮组
    buttonGroup.appendChild(copyButton);
    buttonGroup.appendChild(watermarkBtn);

    // 将按钮组添加到页面
    document.body.appendChild(buttonGroup);

    // 移除之前直接添加到body的按钮
    const oldButtons = document.querySelectorAll('button[style*="position: fixed"]');
    oldButtons.forEach(btn => btn.remove());
})();