让你的飞书更好用(优化版)

让飞书文档不受权限限制,可以复制任意内容,可以打开右键菜单(复制下载图片)

// ==UserScript==
// @name         让你的飞书更好用(优化版)
// @license      GPL License
// @namespace    https://bytedance.com
// @version      0.5
// @description  让飞书文档不受权限限制,可以复制任意内容,可以打开右键菜单(复制下载图片)
// @author       NOABC
// @match        *://*.feishu.cn/*
// @match        *://*.larkoffice.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=feishu.cn
// @grant        none
// @run-at       document-start
// ==/UserScript==
(function () {
    // Override addEventListener to handle copy and contextmenu events
    const overrideEventListeners = () => {
        const rawAddEventListener = EventTarget.prototype.addEventListener;
        EventTarget.prototype.addEventListener = function (type, listener, options) {
            if (type === 'copy') {
                rawAddEventListener.call(this, type, event => {
                    event.stopImmediatePropagation();
                    return null;
                }, options);
                return;
            }
            if (type === 'contextmenu') {
                rawAddEventListener.call(this, type, event => {
                    event.stopImmediatePropagation();
                    return listener(event);
                }, options);
                return;
            }
            rawAddEventListener.call(this, type, listener, options);
        };
    };

    // Override XMLHttpRequest to manipulate permission responses
    const overrideXHR = () => {
        const rawOpen = XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open = function (method, url, ...rest) {
            this.addEventListener('readystatechange', function () {
                if (this.readyState === 4 && url.includes('space/api/suite/permission/document/actions/state/')) {
                    let response = this.responseText;
                    try {
                        response = JSON.parse(response);
                        if (response.data && response.data.actions && response.data.actions.copy !== 1) {
                            response.data.actions.copy = 1;
                            Object.defineProperty(this, 'responseText', { value: JSON.stringify(response) });
                            Object.defineProperty(this, 'response', { value: response });
                        }
                    } catch (e) {
                        console.error('Failed to modify response:', e);
                    }
                }
            }, false);
            rawOpen.call(this, method, url, ...rest);
        };
    };

    // Run overrides immediately and on DOMContentLoaded
    overrideEventListeners();
    overrideXHR();
    document.addEventListener('DOMContentLoaded', () => {
        overrideEventListeners();
        overrideXHR();
    });
})();