Greasy Fork

腾讯元宝/谷歌ai/扣子文件盒子上传增强

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

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

// 1.4更新:支持谷歌aistudio


(function () {
    'use strict';

    const UNSUPPORTED_EXT = ['.dart', '.py', '.java', '.js', '.cpp', '.kt', '.swift', '.html', '.css', '.scss',
        '.php', '.c', '.vbs', '.xml', '.ini', '.md', '.yml', '.yaml', '.cmd', '.bat', '.rs', '.go', '.ts', '.json',
        '.sql', '.rb', '.cs', '.pl', '.lua', '.toml'];

    let eventsInitialized = false;

    function checkCozeCondition() {
        if (window.location.hostname.includes('www.coze.cn')) {
            const targetElement = document.querySelector('#semi-modal-body > div > div');
            if (targetElement && !eventsInitialized) {
                initDropEvent();
                eventsInitialized = true;
                return true;
            }
        } else if (
            (window.location.hostname.includes('yuanbao.tencent.com') ||
                window.location.hostname.includes('aistudio.google.com')) &&
            !eventsInitialized
        ) {
            initPasteEvent();
            initDropEvent();
            eventsInitialized = true;
            return true;
        }
        return false;
    }

    function initPasteEvent() {
        document.addEventListener('paste', handlePaste, true);
    }

    function initDropEvent() {
        document.addEventListener('drop', handleDrop, true);
    }

    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 handlePaste(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);
            }
        }
    }

    function handleDrop(e) {
        // 检测脚本生成标记
        if (e.dataTransfer.types.includes('application/x-script-processed')) return;

        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));
            newData.setData('application/x-script-processed', 'true'); // 添加标记

            // 创建完整拖放事件序列
            ['dragenter', 'dragover', 'drop'].forEach(eventName => {
                const event = new DragEvent(eventName, {
                    bubbles: true,
                    cancelable: true,
                    dataTransfer: newData
                });

                // 强制设置dataTransfer属性
                Object.defineProperty(event, 'dataTransfer', {
                    value: newData,
                    enumerable: true
                });

                e.target.dispatchEvent(event);
            });

            // 特殊处理文件输入
            if (e.target.tagName === 'INPUT' && e.target.type === 'file') {
                e.target.files = newData.files;
            }
        }
    }

    // 初始检测
    checkCozeCondition();

    // 动态监听(仅扣子需要)
    const observer = new MutationObserver(() => {
        if (!eventsInitialized) checkCozeCondition();
    });
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

})();