Greasy Fork

Greasy Fork is available in English.

防止未经授权的自动复制

在非选词复制时显示小红点提示用户以防止未经授权的自动复制,脚本菜单还增加了禁止写入剪贴板功能。

当前为 2024-12-30 提交的版本,查看 最新版本

// ==UserScript==
// @name         防止未经授权的自动复制
// @version      24
// @description  在非选词复制时显示小红点提示用户以防止未经授权的自动复制,脚本菜单还增加了禁止写入剪贴板功能。
// @grant        GM_setClipboard
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-start
// @match        *://*/*
// @namespace    http://greasyfork.icu/users/452911 
// ==/UserScript==

(function() {
    'use strict';

    // 获取当前域名
    const domain = window.location.hostname;

    // 获取当前域名对应的脚本启用状态
    let isClipboardEnabled = GM_getValue(domain + "_clipboard", true); // 默认启用剪贴板操作
    let isCopyEventEnabled = GM_getValue(domain + "_copyEvent", true);

    // 创建油猴菜单:启用/禁用剪贴板操作,启用/禁用复制事件提示
    GM_registerMenuCommand(isClipboardEnabled ? '点击禁止剪贴板写入' : '点击允许剪贴板写入', () => {
        isClipboardEnabled = !isClipboardEnabled; // 切换剪贴板操作启用状态
        GM_setValue(domain + "_clipboard", isClipboardEnabled); // 保存启用状态
        toggleClipboardProtection(isClipboardEnabled); // 动态启用/禁用剪贴板操作
        window.location.reload(); // 刷新网页
    });

    GM_registerMenuCommand(isCopyEventEnabled ? '禁用复制事件提示' : '启用复制事件提示', () => {
        isCopyEventEnabled = !isCopyEventEnabled; // 切换复制事件启用状态
        GM_setValue(domain + "_copyEvent", isCopyEventEnabled); // 保存启用状态
        if (!isCopyEventEnabled) {
            window.location.reload(); // 刷新网页
        }
    });

    // 初始状态下动态启用或禁用剪贴板操作
    toggleClipboardProtection(isClipboardEnabled);

    if (!isCopyEventEnabled) return; // 如果复制事件提示被禁用,则不执行以下代码

    let hasCopied = false;
    let timeoutId = null;
    let dot = null;

    // 处理复制事件
    const handleCopy = function(event) {
        event.preventDefault();
        const selection = window.getSelection().toString();
        if (!hasCopied && selection.trim().length > 0) {
            hasCopied = true;
            createDot(selection);
        }
    };

    // 创建红色提示点
    const createDot = function(selection) {
        dot = document.createElement('div');
        dot.style.width = '20px';
        dot.style.height = '20px';
        dot.style.zIndex = '9999';
        dot.style.background = 'rgba(255, 0, 0, 0.2)';
        dot.style.borderRadius = '50%';
        dot.style.position = 'fixed';
        dot.style.top = '50%';
        dot.style.right = '10px';
        dot.style.transform = 'translateY(-50%)';
        dot.style.cursor = 'pointer';

        dot.addEventListener('click', function() {
            const shouldCopy = confirm(selection);
            if (shouldCopy) {
                if (typeof GM_setClipboard === "function") {
                    GM_setClipboard(selection);
                } else {
                    copyToClipboard(selection);
                }
            }
            document.body.removeChild(dot);
            hasCopied = false;
        });

        document.body.appendChild(dot);

        timeoutId = setTimeout(function() {
            if (dot && dot.parentNode) {
                document.body.removeChild(dot);
            }
            hasCopied = false;
            timeoutId = null;
        }, 4000);
    };

    // 复制到剪贴板的辅助函数
    const copyToClipboard = function(text) {
        const textArea = document.createElement('textarea');
        textArea.value = text;
        document.body.appendChild(textArea);
        textArea.select();
        document.execCommand('copy');
        document.body.removeChild(textArea);
    };

    // 重写navigator.clipboard.writeText
    navigator.clipboard.writeText = function(text) {
        return new Promise((resolve, reject) => {
            copyToClipboard(text);
            resolve();
        });
    };

    // 监听复制事件
    document.addEventListener('copy', handleCopy, { capture: true });

    // 监听页面卸载事件,清除定时器
    window.addEventListener('beforeunload', function() {
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
    });

    let startX = null;
    let startY = null;

    // 监听触摸事件,防止触摸滑动时误触复制
    document.addEventListener('touchstart', function(e) {
        startX = e.touches[0].clientX;
        startY = e.touches[0].clientY;
    });

    document.addEventListener('touchmove', function(e) {
        const currentX = e.touches[0].clientX;
        const currentY = e.touches[0].clientY;
        const diffX = Math.abs(currentX - startX);
        const diffY = Math.abs(currentY - startY);

        if ((diffX > 10 || diffY > 10) && dot) {
            document.body.removeChild(dot);
            hasCopied = false;
            if (timeoutId) {
                clearTimeout(timeoutId);
                timeoutId = null;
            }
        }
    });

    // 动态禁用剪贴板相关操作
    function toggleClipboardProtection(enabled) {
        if (!enabled) {
            // 禁用剪贴板操作
            ['execCommand', 'writeText', 'write'].forEach(method => {
                const target = method === 'execCommand' ? document : navigator.clipboard;
                Object.defineProperty(target, method, {
                    value: () => {
                        console.log(`禁止使用 ${method} 方法`);
                    },
                    writable: false,
                    configurable: false
                });
            });
        }
    }
})();