Greasy Fork

Greasy Fork is available in English.

TX元宝/扣子文件盒子上传增强

粘贴或拖放时自动为代码文件添加.txt后缀并修正MIME类型,使其可正常上传。可能仍会提示不支持,但看到上传成功即可。目前选择上传方式尚未修改。

当前为 2025-02-23 提交的版本,查看 最新版本

// ==UserScript==
// @name         TX元宝/扣子文件盒子上传增强
// @namespace    https://gist.github.com/youzhiran/4fc8fa8a34c35c34ab455cd3f76d8236
// @version      1.2
// @description  粘贴或拖放时自动为代码文件添加.txt后缀并修正MIME类型,使其可正常上传。可能仍会提示不支持,但看到上传成功即可。目前选择上传方式尚未修改。
// @author       yooyi
// @match        *://yuanbao.tencent.com/*
// @match        *://www.coze.cn/space/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const UNSUPPORTED_EXT = ['.dart', '.py', '.java', '.js', '.cpp', '.kt', '.swift', '.html', '.css', '.sql',
        '.php', '.c', '.vbs', '.xml', '.ini', '.md', '.yml', '.yaml', '.cmd', '.bat'];

    // 添加域名和元素检测
    function checkCozeCondition() {
        if (window.location.hostname.includes('www.coze.cn')) {
            const targetElement = document.querySelector('#semi-modal-body > div > div');
            if (targetElement) {
                dropEvent();
                return true;
            }
        }
        if (window.location.hostname.includes('yuanbao.tencent.com')) {
            // 处理粘贴事件
            pasteEvent();
            dropEvent();
        }
        return false;
    }

    // 初始化检测
    checkCozeCondition();
    // 动态监听 DOM 变化
    const observer = new MutationObserver(() => {
        if (checkCozeCondition()) {
            observer.disconnect();
        }
    });
    observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: false,
        characterData: false
    });

    // 公共文件处理函数
    function processFile(file) {
        const originalName = file.name;
        if (UNSUPPORTED_EXT.some(ext => originalName.toLowerCase().endsWith(ext))) {
            return new File([file], `${originalName}.txt`, {type: 'text/plain'});
        }
        return file;
    }

    function pasteEvent() {
        document.addEventListener('paste', function (e) {
            const items = e.clipboardData.items;
            const files = [];
            let shouldModify = false;

            for (let i = 0; i < items.length; i++) {
                const item = items[i];
                if (item.kind === 'file') {
                    const file = item.getAsFile();
                    const processedFile = processFile(file);
                    files.push(processedFile);
                    if (processedFile !== file) shouldModify = true;
                }
            }

            if (shouldModify) {
                e.preventDefault();
                const newData = new DataTransfer();
                files.forEach(f => newData.items.add(f));

                const target = document.activeElement.closest('input, [contenteditable]') || document.activeElement;
                if (target instanceof HTMLInputElement) {
                    target.files = newData.files;
                } else {
                    const pasteEvent = new ClipboardEvent('paste', {
                        clipboardData: newData,
                        bubbles: true,
                        cancelable: true
                    });
                    target.dispatchEvent(pasteEvent);
                }
            }
        }, true);
    }

    function dropEvent() {
        document.addEventListener('drop', function (e) {
            const items = e.dataTransfer.items;
            if (!items.length) return;

            const files = [];
            let shouldModify = false;

            for (let i = 0; i < items.length; i++) {
                const item = items[i];
                if (item.kind === 'file') {
                    const file = item.getAsFile();
                    const processedFile = processFile(file);
                    files.push(processedFile);
                    if (processedFile !== file) shouldModify = true;
                }
            }

            if (shouldModify) {
                e.preventDefault();
                e.stopPropagation();

                const newData = new DataTransfer();
                files.forEach(f => newData.items.add(f));

                // // 通过粘贴事件传递文件
                // const target = document.activeElement;
                // if (target instanceof HTMLInputElement) {
                //     target.files = newData.files;
                // } else {
                //     const pasteEvent = new ClipboardEvent('paste', {
                //         clipboardData: newData,
                //         bubbles: true,
                //         cancelable: true
                //     });
                //     target.dispatchEvent(pasteEvent);
                // }
                // 创建完整的拖放事件序列
                ['dragenter', 'dragover', 'drop'].forEach(eventName => {
                    const event = new DragEvent(eventName, {
                        bubbles: true,
                        cancelable: true,
                        dataTransfer: newData
                    });
                    Object.defineProperty(event, 'dataTransfer', {
                        value: newData,
                        enumerable: true
                    });
                    e.target.dispatchEvent(event);
                });
                // 触发 change 事件更新文件输入
                if (e.target.tagName === 'INPUT' && e.target.type === 'file') {
                    e.target.files = newData.files;
                    const changeEvent = new Event('change', {bubbles: true});
                    e.target.dispatchEvent(changeEvent);
                }

            }

        }, true);
    }


})();