Greasy Fork

Greasy Fork is available in English.

Google AI Studio 模型注入器

向 Google AI Studio 注入自定义模型,支持在模型列表中手动添加ID(无需输入 models/)。拦截 XHR/Fetch 请求。

// ==UserScript==
// @name         Google AI Studio 模型注入器
// @namespace    http://tampermonkey.net/
// @version      1.7.1
// @description  向 Google AI Studio 注入自定义模型,支持在模型列表中手动添加ID(无需输入 models/)。拦截 XHR/Fetch 请求。
// @author       Generated by AI / HCPTangHY / Mozi / wisdgod / UserModified / Yefori
// @match        https://aistudio.google.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=aistudio.google.com
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 配置管理 ====================
    /**
     * 脚本全局配置
     * @const
     */
    const CONFIG = {
        VERSION: "1.7.1",
        STORAGE_KEY: 'AI_STUDIO_INJECTOR_CUSTOM_MODELS',
        API: {
            ANTI_HIJACK_PREFIX: ")]}'\n",
            TARGET_PATH: '/ListModels',
            TARGET_HOST: 'alkalimakersuite'
        },
        MODEL_PREFIX: 'models/',
        FIELD_INDEX: {
            NAME: 0,
            DISPLAY_NAME: 3,
            DESCRIPTION: 4,
            METHODS: 7
        }
    };

    // ==================== 日志管理 ====================
    /**
     * 统一的日志管理器
     * @namespace Logger
     */
    const Logger = {
        prefix: `[AI Studio 注入器 v${CONFIG.VERSION}]`,

        /**
         * 输出常规日志
         * @param {...any} args - 日志内容
         */
        log(...args) {
            console.log(this.prefix, ...args);
        },

        /**
         * 输出错误日志
         * @param {...any} args - 错误内容
         */
        error(...args) {
            console.error(this.prefix, ...args);
        },

        /**
         * 输出警告日志
         * @param {...any} args - 警告内容
         */
        warn(...args) {
            console.warn(this.prefix, ...args);
        }
    };

    // ==================== 存储管理 ====================
    /**
     * 本地存储管理器,处理自定义模型的持久化
     * @namespace Storage
     */
    const Storage = {
        /**
         * 从本地存储加载自定义模型列表
         * @returns {Array<Object>} 自定义模型数组,包含name、displayName和description字段
         */
        load() {
            try {
                const data = localStorage.getItem(CONFIG.STORAGE_KEY);
                if (data) {
                    const models = JSON.parse(data);
                    // 自动更新模型的版本标记以匹配当前脚本版本
                    return models.map(model => ({
                        ...model,
                        displayName: model.displayName.replace(/ \(脚本 v[\d.]+\)$/, '') + ` (脚本 v${CONFIG.VERSION})`,
                        description: model.description.replace(/脚本 v[\d.]+/, `脚本 v${CONFIG.VERSION}`)
                    }));
                }
            } catch (e) {
                Logger.error('加载自定义模型时出错:', e);
            }
            return [];
        },

        /**
         * 保存自定义模型列表到本地存储
         * @param {Array<Object>} models - 要保存的模型数组
         * @returns {boolean} 保存是否成功
         */
        save(models) {
            try {
                localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(models));
                return true;
            } catch (e) {
                Logger.error('保存自定义模型时出错:', e);
                return false;
            }
        }
    };

    // ==================== 工具函数 ====================
    /**
     * 通用工具函数集合
     * @namespace Utils
     */
    const Utils = {
        /**
         * 清理模型名称,移除版本标记和emoji前缀
         * @param {string} name - 原始模型名称
         * @returns {string} 清理后的名称
         */
        cleanModelName(name) {
            return String(name)
                .replace(/ \(脚本 v\d+\.\d+(\.\d+)?\)/, '')
                .replace(/^[✨🦁💧❄️🌊🐉🏴‍☠️🤖🪐]\s*/, '')
                .trim();
        },

        /**
         * 格式化模型显示名称,添加版本标记
         * @param {string} displayName - 原始显示名称
         * @returns {string} 带版本标记的显示名称
         */
        formatDisplayName(displayName) {
            const cleanName = displayName.replace(/ \(脚本 v[\d.]+\)$/, '');
            return `${cleanName} (脚本 v${CONFIG.VERSION})`;
        },

        /**
         * 格式化模型描述,更新版本信息
         * @param {string} description - 原始描述
         * @returns {string} 更新版本后的描述
         */
        formatDescription(description) {
            return description.replace(/脚本 v[\d.]+/, `脚本 v${CONFIG.VERSION}`);
        },

        /**
         * 检查URL是否匹配需要拦截的模型列表API
         * @param {string} url - 要检查的URL
         * @returns {boolean} 是否为目标URL
         */
        isTargetURL(url) {
            return url && typeof url === 'string' &&
                   url.includes(CONFIG.API.TARGET_HOST) &&
                   url.includes(CONFIG.API.TARGET_PATH);
        },

        /**
         * 验证模型ID是否有效
         * @param {string} id - 模型ID
         * @returns {boolean} ID是否有效
         */
        validateModelId(id) {
            if (!id || typeof id !== 'string') return false;
            const trimmed = id.trim();
            return trimmed.length > 0;
        },

        /**
         * 确保模型ID具有正确的前缀
         * @param {string} id - 原始模型ID
         * @returns {string} 带正确前缀的模型ID
         */
        ensureModelPrefix(id) {
            const trimmed = id.trim();
            return trimmed.startsWith(CONFIG.MODEL_PREFIX) ? trimmed : CONFIG.MODEL_PREFIX + trimmed;
        }
    };

    // ==================== 模型定义 ====================
    /**
     * 特殊动作模型:添加自定义模型
     * @const
     */
    const ACTION_ADD_MODEL = {
        name: 'models/---script-action-add-custom---',
        displayName: `➕ 添加自定义模型 (点击此处)`,
        description: '点击此项以手动输入新的模型 ID 并保存。'
    };

    /**
     * 特殊动作模型:清除所有自定义模型
     * @const
     */
    const ACTION_CLEAR_MODELS = {
        name: 'models/---script-action-clear-custom---',
        displayName: `🗑️ 清除手动添加的模型 (点击此处)`,
        description: '点击此项以清除所有您手动添加的模型。'
    };

    /**
     * 预设模型列表
     * @const
     */
    const PREDEFINED_MODELS = [
    {
        name: "models/blacktooth-ab-test",
        displayName: `🏴‍☠️ Blacktooth (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/jfdksal98a",
        displayName: `🪐 jfdksal98a (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    // --- 新添加的模型开始 ---
    {
        name: "models/68zkqbz8vs",
        displayName: `🤖 68zkqbz8vs (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/a24bo28u1a",
        displayName: `🚀 a24bo28u1a (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/2vmc1bo4ri",
        displayName: `💡 2vmc1bo4ri (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/42fc3y4xfsz",
        displayName: `🔧 42fc3y4xfsz (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
        templateModelName: `models/gemini-2.5-flash-preview-05-20`,
    },
    {
        name: "models/ixqzem8yj4j",
        displayName: `🔮 ixqzem8yj4j (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
        templateModelName: `models/gemini-2.5-flash-preview-05-20`,
    },
    // --- 新添加的模型结束 ---
    {
        name: "models/gemini-2.5-pro-preview-03-25",
        displayName: `✨ Gemini 2.5 Pro 03-25 (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/goldmane-ab-test",
        displayName: `🦁 Goldmane (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/claybrook-ab-test",
        displayName: `💧 Claybrook (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/frostwind-ab-test",
        displayName: `❄️ Frostwind (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    {
        name: "models/calmriver-ab-test",
        displayName: `🌊 Calmriver (脚本 v${CONFIG.VERSION})`,
        description: `由脚本 v${CONFIG.VERSION} 预设注入的模型`,
    },
    ];


    // ==================== 自定义模型管理 (UI 逻辑) ====================

    /**
     * 通过对话框收集用户输入并创建新的自定义模型
     */
    function promptForNewModel() {
        // 提示用户输入模型ID,会自动添加 'models/' 前缀
        const rawInputId = prompt("【添加自定义模型】\n请输入新的模型ID (例如: my-custom-model):\n(会自动添加 'models/' 前缀)");
        if (!rawInputId) return;

        if (!Utils.validateModelId(rawInputId)) {
            alert("错误:模型ID不能为空。");
            return;
        }

        // 自动添加 'models/' 前缀
        const fullModelId = Utils.ensureModelPrefix(rawInputId);

        // 使用模型ID生成默认显示名称
        const defaultName = fullModelId.split('/').pop();
        const displayNameInput = prompt("请输入该模型的显示名称 (例如: 🤖 我的模型):", `🤖 ${defaultName}`);
        if (!displayNameInput) return;

        const newModel = {
            name: fullModelId,
            displayName: Utils.formatDisplayName(displayNameInput),
            description: `由用户手动添加并通过脚本 v${CONFIG.VERSION} 注入的模型`
        };

        const customModels = Storage.load();
        const allCurrentModels = [...PREDEFINED_MODELS, ...customModels];

        // 检查模型ID是否已存在
        if (allCurrentModels.some(m => m.name === fullModelId)) {
            alert(`错误:模型ID ${fullModelId} 已存在。`);
            return;
        }

        customModels.push(newModel);
        if (Storage.save(customModels)) {
            alert(`模型 ${fullModelId} 添加成功!\n\n页面将自动刷新以应用更改。`);
            window.location.reload();
        } else {
            alert("错误:无法保存模型。");
        }
    }

    /**
     * 清除所有用户自定义的模型(不影响预设模型)
     */
    function clearAllCustomModels() {
        if (confirm("⚠️ 确定要清除所有您手动添加的自定义模型吗?\n\n(脚本预设的模型不会被删除)")) {
            if (Storage.save([])) {
                alert("所有手动添加的自定义模型已清除。页面将自动刷新。");
                window.location.reload();
            } else {
                alert("错误:无法清除模型。");
            }
        }
    }

    /**
     * 设置模型选择器的点击事件拦截器,用于处理动作模型的点击
     */
    function setupModelSelectionInterceptor() {
        document.body.addEventListener('click', (event) => {
            const optionElement = event.target.closest('[role="option"], mat-option');

            if (optionElement && optionElement.textContent) {
                const text = optionElement.textContent;
                let actionTaken = false;

                if (text.includes(ACTION_ADD_MODEL.displayName)) {
                    Logger.log("拦截到 '添加模型' 点击事件。");
                    actionTaken = true;
                    setTimeout(promptForNewModel, 50);
                } else if (text.includes(ACTION_CLEAR_MODELS.displayName)) {
                    Logger.log("拦截到 '清除模型' 点击事件。");
                    actionTaken = true;
                    setTimeout(clearAllCustomModels, 50);
                }

                if (actionTaken) {
                    // 阻止默认行为和事件冒泡
                    event.preventDefault();
                    event.stopPropagation();
                    // 移除焦点以关闭下拉菜单
                    if (document.activeElement) {
                        document.activeElement.blur();
                    }
                }
            }
        }, true); // 在捕获阶段处理事件
        Logger.log('模型选择点击拦截器已设置。');
    }

    // ==================== 初始化 ====================

    const customModels = Storage.load();
    const ALL_MODELS_TO_INJECT = [...PREDEFINED_MODELS, ...customModels];

    Logger.log(`预设模型: ${PREDEFINED_MODELS.length} 个, 用户自定义模型: ${customModels.length} 个`);

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', setupModelSelectionInterceptor);
    } else {
        setupModelSelectionInterceptor();
    }

    // ==================== 数据处理工具函数 ====================

    /**
     * 递归查找响应数据中的模型列表数组
     * @param {Object} obj - 要搜索的对象
     * @returns {Array|null} 找到的模型数组或null
     */
    function findModelListArray(obj) {
        if (!obj) return null;

        // 检查是否为有效的模型数组
        if (Array.isArray(obj) && obj.length > 0 && obj.every(
            item => Array.isArray(item) &&
                    typeof item[CONFIG.FIELD_INDEX.NAME] === 'string' &&
                    String(item[CONFIG.FIELD_INDEX.NAME]).startsWith('models/')
        )) {
            return obj;
        }

        // 递归搜索对象的所有属性
        if (typeof obj === 'object') {
            for (const key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, key) && typeof obj[key] === 'object' && obj[key] !== null) {
                    const result = findModelListArray(obj[key]);
                    if (result) return result;
                }
            }
        }
        return null;
    }

    /**
     * 查找合适的模板模型用于创建新模型条目
     * @param {Array} modelsArray - 模型数组
     * @returns {Array|undefined} 找到的模板模型
     */
    function findTemplateModel(modelsArray) {
        // 优先选择包含 'pro' 的模型作为模板
        return modelsArray.find(m => Array.isArray(m) && m[CONFIG.FIELD_INDEX.NAME] && String(m[CONFIG.FIELD_INDEX.NAME]).includes('pro') && Array.isArray(m[CONFIG.FIELD_INDEX.METHODS])) ||
               // 次选包含 'flash' 的模型
               modelsArray.find(m => Array.isArray(m) && m[CONFIG.FIELD_INDEX.NAME] && String(m[CONFIG.FIELD_INDEX.NAME]).includes('flash') && Array.isArray(m[CONFIG.FIELD_INDEX.METHODS])) ||
               // 最后选择任意有方法列表的模型
               modelsArray.find(m => Array.isArray(m) && m[CONFIG.FIELD_INDEX.NAME] && Array.isArray(m[CONFIG.FIELD_INDEX.METHODS]));
    }

    /**
     * 根据模型名称查找合适的模板模型用于创建新模型条目
     * @param {Array} modelsArray - 模型数组
     * @param {String} modelName - 模板模型名称
     * @returns {Array|undefined} 找到的模板模型
     */
    function findTemplateModelByModelName(modelsArray, modelName) {
        return modelsArray.find(m => Array.isArray(m) && m[CONFIG.FIELD_INDEX.NAME] && String(m[CONFIG.FIELD_INDEX.NAME]) === modelName && Array.isArray(m[CONFIG.FIELD_INDEX.METHODS]));
    }

    /**
     * 更新已存在的模型条目
     * @param {Array} existingModel - 现有模型数组
     * @param {Object} modelToInject - 要注入的模型配置
     * @returns {boolean} 是否成功更新(true表示已更新,无需再注入新条目)
     */
    function updateExistingModel(existingModel, modelToInject) {
        if (!existingModel || existingModel[CONFIG.FIELD_INDEX.DISPLAY_NAME] === modelToInject.displayName) {
            return false;
        }

        const baseExistingName = Utils.cleanModelName(existingModel[CONFIG.FIELD_INDEX.DISPLAY_NAME]);
        const baseInjectName = Utils.cleanModelName(modelToInject.displayName);

        if (baseExistingName === baseInjectName) {
            // 基础名称相同,更新版本标记
            existingModel[CONFIG.FIELD_INDEX.DISPLAY_NAME] = modelToInject.displayName;
            return true;
        } else {
            // 基础名称不同,标记为原始版本
            if (!String(existingModel[CONFIG.FIELD_INDEX.DISPLAY_NAME]).includes("(原始)")) {
                 existingModel[CONFIG.FIELD_INDEX.DISPLAY_NAME] += " (原始)";
            }
            return false;
        }
    }

    /**
     * 基于模板创建新的模型条目
     * @param {Array} templateModel - 模板模型
     * @param {Object} modelToInject - 要注入的模型配置
     * @param {string} templateName - 模板模型名称
     * @returns {Array} 新创建的模型条目
     */
    function createNewModel(templateModel, modelToInject, templateName) {
        const newModel = structuredClone(templateModel);
        newModel[CONFIG.FIELD_INDEX.NAME] = modelToInject.name;
        newModel[CONFIG.FIELD_INDEX.DISPLAY_NAME] = modelToInject.displayName;
        newModel[CONFIG.FIELD_INDEX.DESCRIPTION] = `${modelToInject.description} (基于 ${templateName} 结构)`;

        // 确保有方法列表
        if (!Array.isArray(newModel[CONFIG.FIELD_INDEX.METHODS])) {
            newModel[CONFIG.FIELD_INDEX.METHODS] = [
                "generateContent", "countTokens", "createCachedContent", "batchGenerateContent"
            ];
        }
        return newModel;
    }

    // ==================== 核心处理函数 ====================

    /**
     * 处理API响应数据,注入自定义模型
     * @param {Object} jsonData - 原始JSON响应数据
     * @param {string} url - 请求URL
     * @returns {{data: Object, modified: boolean}} 处理结果
     */
    function processJsonData(jsonData, url) {
        let modificationMade = false;
        const modelsArray = findModelListArray(jsonData);

        if (!modelsArray) return { data: jsonData, modified: false };

        const generalTemplateModel = findTemplateModel(modelsArray);
        const generalTemplateName = generalTemplateModel?.[CONFIG.FIELD_INDEX.NAME] || 'unknown';

        if (!generalTemplateModel) {
            Logger.warn('未找到模板模型');
            return { data: jsonData, modified: false };
        }

        // 注入自定义和预设模型
        [...ALL_MODELS_TO_INJECT].reverse().forEach(modelToInject => {
            const existingModel = modelsArray.find(
                model => Array.isArray(model) && model[CONFIG.FIELD_INDEX.NAME] === modelToInject.name
            );

            let shouldInjectNew = true;

            if (existingModel) {
               const updated = updateExistingModel(existingModel, modelToInject);
               modificationMade = modificationMade || updated;
               shouldInjectNew = !updated;
            }

            if (shouldInjectNew) {
                // 检查是否已经注入过脚本版本
                const alreadyInjected = modelsArray.find(m =>
                    Array.isArray(m) &&
                    m[CONFIG.FIELD_INDEX.NAME] === modelToInject.name &&
                    String(m[CONFIG.FIELD_INDEX.DISPLAY_NAME]).includes('(脚本 v')
                );

                if (!alreadyInjected) {
                    let templateModel = generalTemplateModel;
                    let templateName = generalTemplateName;
                    if(modelToInject.templateModelName){
                        templateModel = findTemplateModelByModelName(modelsArray, modelToInject.templateModelName)
                    }
                    let newModel = createNewModel(templateModel, modelToInject, templateName);
                    modelsArray.unshift(newModel);
                    modificationMade = true;
                    Logger.log(`成功注入: ${modelToInject.displayName} 到模板 "${templateName}"`);
                } else {
                    // 更新已注入模型的版本信息
                    if (alreadyInjected[CONFIG.FIELD_INDEX.DISPLAY_NAME] !== modelToInject.displayName) {
                        alreadyInjected[CONFIG.FIELD_INDEX.DISPLAY_NAME] = modelToInject.displayName;
                        alreadyInjected[CONFIG.FIELD_INDEX.DESCRIPTION] = `${modelToInject.description} (基于 ${generalTemplateName} 结构)`;
                        modificationMade = true;
                    }
                }
            }
        });

        // 注入动作模型(添加和清除按钮)
        const addActionModel = createNewModel(generalTemplateModel, ACTION_ADD_MODEL, generalTemplateName);
        addActionModel[CONFIG.FIELD_INDEX.METHODS] = []; // 清空方法列表

        if (customModels.length > 0) {
            const clearActionModel = createNewModel(generalTemplateModel, ACTION_CLEAR_MODELS, generalTemplateName);
            clearActionModel[CONFIG.FIELD_INDEX.METHODS] = [];
            modelsArray.unshift(clearActionModel);
        }
        modelsArray.unshift(addActionModel);

        modificationMade = true;
        Logger.log('已注入"添加/清除自定义模型"动作条目。');

        return { data: jsonData, modified: modificationMade };
    }

    /**
     * 修改HTTP响应体,注入自定义模型数据
     * @param {string} originalText - 原始响应文本
     * @param {string} url - 请求URL
     * @returns {string} 修改后的响应文本
     */
    function modifyResponseBody(originalText, url) {
        if (!originalText || typeof originalText !== 'string') return originalText;

        try {
            let textBody = originalText;
            let hasPrefix = false;

            // 处理Google的反劫持前缀
            if (textBody.startsWith(CONFIG.API.ANTI_HIJACK_PREFIX)) {
                textBody = textBody.substring(CONFIG.API.ANTI_HIJACK_PREFIX.length);
                hasPrefix = true;
            }

            if (!textBody.trim()) return originalText;

            const jsonData = JSON.parse(textBody);
            const result = processJsonData(jsonData, url);

            if (result.modified) {
                let newBody = JSON.stringify(result.data);
                if (hasPrefix) newBody = CONFIG.API.ANTI_HIJACK_PREFIX + newBody;
                return newBody;
            }
        } catch (error) {
            Logger.error('处理响应体时出错:', url, error);
        }
        return originalText;
    }

    // ==================== 请求拦截 ====================

    // 拦截 Fetch API
    const originalFetch = window.fetch;
    window.fetch = async function(...args) {
        const url = (args[0] instanceof Request) ? args[0].url : String(args[0]);
        const response = await originalFetch.apply(this, args);

        if (Utils.isTargetURL(url) && response.ok) {
            try {
                const cloneResponse = response.clone();
                const originalText = await cloneResponse.text();
                const newBody = modifyResponseBody(originalText, url);
                if (newBody !== originalText) {
                    return new Response(newBody, {
                        status: response.status,
                        statusText: response.statusText,
                        headers: response.headers
                    });
                }
            } catch (e) {
                Logger.error('[Fetch] 处理错误:', e);
            }
        }
        return response;
    };

    // 拦截 XMLHttpRequest
    const xhrProto = XMLHttpRequest.prototype;
    const originalOpen = xhrProto.open;
    const originalResponseTextDescriptor = Object.getOwnPropertyDescriptor(xhrProto, 'responseText');
    const originalResponseDescriptor = Object.getOwnPropertyDescriptor(xhrProto, 'response');

    /**
     * 重写XHR的open方法以记录请求URL
     */
    xhrProto.open = function(method, url) {
        this._interceptorUrl = url;
        this._isTargetXHR = Utils.isTargetURL(url);
        return originalOpen.apply(this, arguments);
    };

    /**
     * 处理XHR响应,根据需要修改内容
     * @param {XMLHttpRequest} xhr - XHR对象
     * @param {*} originalValue - 原始响应值
     * @param {string} type - 响应类型 ('text' 或 'json')
     * @returns {*} 处理后的响应值
     */
    const handleXHRResponse = (xhr, originalValue, type = 'text') => {
        if (!xhr._isTargetXHR || xhr.readyState !== 4 || xhr.status !== 200) return originalValue;

        const cacheKey = '_modifiedResponseCache_' + type;
        if (xhr[cacheKey] === undefined) {
            const originalText = (type === 'text' || typeof originalValue !== 'object' || originalValue === null)
                ? String(originalValue || '') : JSON.stringify(originalValue);
            xhr[cacheKey] = modifyResponseBody(originalText, xhr._interceptorUrl);
        }

        const cachedResponse = xhr[cacheKey];
        try {
            if (type === 'json' && typeof cachedResponse === 'string') {
                const textToParse = cachedResponse.replace(CONFIG.API.ANTI_HIJACK_PREFIX, '');
                return textToParse ? JSON.parse(textToParse) : null;
            }
        } catch (e) {
            Logger.error('[XHR] 解析 JSON 时出错:', e);
            return originalValue;
        }
        return cachedResponse;
    };

    // 重写responseText属性
    if (originalResponseTextDescriptor?.get) {
        Object.defineProperty(xhrProto, 'responseText', {
            get: function() {
                const originalText = originalResponseTextDescriptor.get.call(this);
                if (this.responseType && this.responseType !== 'text' && this.responseType !== "") return originalText;
                return handleXHRResponse(this, originalText, 'text');
            },
            configurable: true
        });
    }

    // 重写response属性
    if (originalResponseDescriptor?.get) {
        Object.defineProperty(xhrProto, 'response', {
            get: function() {
                const originalResponse = originalResponseDescriptor.get.call(this);
                if (this.responseType === 'json') return handleXHRResponse(this, originalResponse, 'json');
                if (!this.responseType || this.responseType === 'text' || this.responseType === "") {
                    return handleXHRResponse(this, originalResponse, 'text');
                }
                return originalResponse;
            },
            configurable: true
        });
    }

    Logger.log(`脚本 v${CONFIG.VERSION} 已激活。Fetch 和 XHR 拦截已启用。`);
})();