Text to js

文本转JS工具,智能识别修改油猴脚本元数据

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Text to js
// @namespace    http://tampermonkey.net/
// @version      1.54
// @description  文本转JS工具,智能识别修改油猴脚本元数据
// @author       苳:-)
// @match        *://*/*
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    let codeContent = '';
    let originalHeader = '';
    let originalBody = '';
    let detectedName = '';
    let detectedVersion = '';
    const version = 'v1.54';

    // 更新日志(保持不变)
    const changelog = [
        "v1.54 修复脚本信息识别错误问题",
        "v1.53 修复面板显示问题",
        "v1.52 全面修复规则添加",
        "v1.51 修复粘贴代码下载问题",
        "v1.50 优化下载文件名自动识别",
        "v1.49 优化当前基准显示"
    ];

    // 创建 Shadow DOM 容器
    const host = document.createElement('div');
    document.body.appendChild(host);
    const shadow = host.attachShadow({mode:'open'});

    GM_addStyle(`
        #text2js_panel * { all: initial !important; box-sizing: border-box !important; }
        #text2js_panel { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial !important; }
    `);

    // HTML + 样式 - 统一蓝色执行按钮版
    shadow.innerHTML = `
    <div id="text2js_panel">
        <style>
            #panel{
                position:fixed;
                top:60px;
                right:20px;
                width:90%;
                max-width:400px;
                background:#fff;
                border:1px solid #ccc;
                z-index:999999;
                font-size:13px;
                color:#111;
                box-shadow:0 4px 12px rgba(0,0,0,0.15);
                border-radius:6px;
                transition:all 0.3s ease;
                max-height:80vh;
                overflow-y:auto;
                user-select:none;
            }
            #panel.dragging {
                opacity:0.9;
                box-shadow:0 8px 24px rgba(0,0,0,0.2);
                transition:none;
                cursor:grabbing;
            }
            #panel.minimized{
                transform:scale(0.8);
                opacity:0.9;
                cursor:pointer;
                transform-origin:top right;
                max-height:none;
                overflow:visible;
            }
            #panel.minimized:hover{opacity:1;}

            #panel header{
                background:#111;
                color:#fff;
                padding:14px;
                font-weight:600;
                text-align:left;
                border-top-left-radius:6px;
                border-top-right-radius:6px;
                display:flex;
                justify-content:space-between;
                align-items:center;
                position:sticky;
                top:0;
                z-index:10;
                cursor:grab;
                user-select:none;
            }
            #panel header:active { cursor:grabbing; }
            #panel.minimized header { cursor:pointer; }
            #panel.minimized header:active { cursor:pointer; }

            #panel header .title{
                display:flex;
                align-items:center;
                gap:6px;
            }
            #panel header .title .script-name{
                font-weight:600;
                color:#fff;
            }
            #panel header .title .script-version{
                font-weight:600;
                color:#ffd700;
            }
            #panel header .toggle-btn{
                background:transparent;
                border:none;
                color:#fff;
                font-size:18px;
                cursor:pointer;
                padding:0 8px;
                border-radius:4px;
                line-height:1;
                z-index:11;
            }
            #panel header .toggle-btn:hover{background:rgba(255,255,255,0.2);}

            .author{
                padding:12px;
                border-bottom:1px solid #eee;
                display:flex;
                gap:12px;
                align-items:center;
            }
            .author span{
                font-weight:600;
                color:#111;
            }
            .author a{
                color:#007aff;
                text-decoration:none;
            }

            .file{padding:12px;border-bottom:1px solid #eee;background:#fafafa;}
            .active-source{padding:12px;background:#f5f5f5;border-bottom:1px solid #e0e0e0;font-size:13px;display:flex;align-items:center;gap:8px;}
            .text-editor{padding:12px;border-bottom:1px solid #eee;}
            .info{padding:12px;border-bottom:1px solid #eee;background:#f9f9f9;}
            .edit{padding:12px;border-bottom:1px solid #eee;}
            .action-buttons{padding:12px;display:flex;gap:6px;}

            .file input,
            .text-editor textarea,
            .metadata-field input,
            .metadata-field textarea {
                width:100%;
                border:1px solid #ccc;
                border-radius:4px;
                padding:8px;
                font-size:13px;
                box-sizing:border-box;
            }

            .file input {
                overflow:hidden;
                text-overflow:ellipsis;
                white-space:nowrap;
            }

            .text-editor textarea {
                min-height:100px;
                resize:vertical;
                font-family:monospace;
            }

            .active-source .source-label{font-weight:600;color:#333;}
            .active-source .source-text{color:#1976d2;font-weight:500;}
            .active-source .source-time{color:#666;font-size:12px;margin-left:auto;}

            .text-editor .editor-header{
                display:flex;
                justify-content:space-between;
                align-items:center;
                margin-bottom:6px;
            }
            .text-editor .editor-header .editor-title{font-weight:600;font-size:13px;color:#333;}
            .text-editor .editor-header .clear-text{color:#007aff;cursor:pointer;font-size:12px;}
            .text-editor .editor-header .clear-text:hover{text-decoration:underline;}

            .info-header{
                cursor:pointer;
                font-weight:600;
                display:flex;
                justify-content:space-between;
                align-items:center;
            }
            .info-header .toggle-text{color:#007aff;font-size:12px;font-weight:normal;}
            .info-content{
                margin-top:8px;
                display:none;
                font-size:12px;
                color:#333;
                max-height:120px;
                overflow-y:auto;
                white-space:pre-line;
            }

            .edit-header{
                cursor:pointer;
                font-weight:600;
                display:flex;
                justify-content:space-between;
                align-items:center;
            }
            .edit-header .toggle-text{color:#007aff;font-size:12px;font-weight:normal;}
            .edit-content{margin-top:10px;display:none;}

            .metadata-section{margin-bottom:15px;}
            .metadata-section .section-header{
                font-weight:600;
                margin-bottom:8px;
                color:#333;
                font-size:12px;
                padding-bottom:2px;
                border-bottom:1px solid #eee;
            }
            .metadata-field{margin-bottom:12px;}
            .metadata-field label{
                display:block;
                font-size:12px;
                color:#666;
                margin-bottom:2px;
            }

            .metadata-field textarea{min-height:60px;resize:vertical;}

            .advanced-toggle{
                margin:10px 0;
                display:flex;
                align-items:center;
                gap:8px;
            }
            .advanced-toggle .toggle-switch{
                position:relative;
                display:inline-block;
                width:36px;
                height:20px;
            }
            .advanced-toggle .toggle-switch input{opacity:0;width:0;height:0;}
            .advanced-toggle .slider{
                position:absolute;
                cursor:pointer;
                top:0;
                left:0;
                right:0;
                bottom:0;
                background-color:#ccc;
                transition:.2s;
                border-radius:20px;
            }
            .advanced-toggle .slider:before{
                position:absolute;
                content:"";
                height:16px;
                width:16px;
                left:2px;
                bottom:2px;
                background-color:white;
                transition:.2s;
                border-radius:50%;
            }
            .advanced-toggle input:checked + .slider{background-color:#007aff;}
            .advanced-toggle input:checked + .slider:before{transform:translateX(16px);}
            .advanced-toggle .toggle-label{font-size:12px;color:#666;}

            .advanced-content{
                margin-top:10px;
                padding-top:10px;
                border-top:1px solid #eee;
                display:none;
            }

            /* 简化按钮样式 - 统一为蓝色 */
            .action-buttons button{
                flex:1;
                padding:10px 0;
                border:none;
                border-radius:4px;
                color:#fff;
                font-size:14px;
                cursor:pointer;
                transition:transform 0.1s, background-color 0.2s;
                font-weight:500;
            }
            .action-buttons button:active{transform:scale(0.95);}

            /* 执行按钮 - 始终蓝色 */
            .action-buttons .execute-btn{
                background:#007aff;  /* 统一蓝色 */
            }
            .action-buttons .execute-btn:hover{
                background:#0051b3;  /* 深蓝色悬停效果 */
            }
            .action-buttons .execute-btn.disabled{
                background:#b0b0b0;  /* 灰色表示不可用 */
                cursor:not-allowed;
            }

            /* 清空按钮保持红色 */
            .action-buttons .clear-btn{
                background:#f44336;
            }
            .action-buttons .clear-btn:hover{
                background:#d32f2f;
            }

            .status-badge{
                background:#4CAF50;
                color:#fff;
                font-size:10px;
                padding:2px 6px;
                border-radius:10px;
                margin-left:6px;
            }
            .status-badge.na{background:#9e9e9e;}
        </style>

        <div id="panel">
            <header id="dragHandle">
                <div class="title">
                    <span class="script-name">Text to js</span>
                    <span class="script-version">${version}</span>
                </div>
                <button class="toggle-btn" id="togglePanel">−</button>
            </header>

            <div id="panelContent">
                <!-- 作者信息 -->
                <div class="author">
                    <span>作者 苳:-)</span>
                    <a href="https://weibo.com/u/2809762605" target="_blank">Weibo</a>
                    <a href="https://x.com/nkvvo?s=21" target="_blank">Twitter</a>
                </div>

                <!-- 文件选择 -->
                <div class="file">
                    <input type="file" accept=".txt,.js" id="fileInput" placeholder="选择TXT或JS文件...">
                </div>

                <!-- 当前基准提示 -->
                <div class="active-source" id="activeSource">
                    <span class="source-label">当前基准</span>
                    <span class="source-text" id="sourceText">未选择内容</span>
                    <span class="source-time" id="sourceTime"></span>
                </div>

                <!-- 文本编辑框 -->
                <div class="text-editor">
                    <div class="editor-header">
                        <span class="editor-title">填入代码</span>
                        <span class="clear-text" id="clearTextBtn">清空</span>
                    </div>
                    <textarea id="codeEditor" placeholder="可在此粘贴JS或TXT代码..."></textarea>
                </div>

                <!-- 脚本信息模块 -->
                <div class="info">
                    <div class="info-header">
                        <span>脚本信息</span>
                        <span class="toggle-text" id="infoToggle">展开</span>
                    </div>
                    <div class="info-content" id="infoContent">
脚本介绍:文本转 JS 文件工具,支持TXT转JS和JS元数据修改。
当前版本:${version}
更新日志:
${changelog.join('\n')}
                    </div>
                </div>

                <!-- 脚本修改模块 -->
                <div class="edit">
                    <div class="edit-header">
                        <div>
                            <span>脚本修改</span>
                            <span class="status-badge na" id="headerStatus">未检测</span>
                        </div>
                        <span class="toggle-text" id="editToggle">展开</span>
                    </div>
                    <div class="edit-content" id="editContent">
                        <!-- 基础信息 -->
                        <div class="metadata-section">
                            <div class="section-header">基础信息</div>
                            <div class="metadata-field">
                                <label>@name 脚本名称</label>
                                <input type="text" id="metaName" placeholder="脚本名称">
                            </div>
                            <div class="metadata-field">
                                <label>@namespace 命名空间</label>
                                <input type="text" id="metaNamespace" placeholder="http://tampermonkey.net/">
                            </div>
                            <div class="metadata-field">
                                <label>@version 版本号</label>
                                <input type="text" id="metaVersion" placeholder="1.0.0">
                            </div>
                            <div class="metadata-field">
                                <label>@description 描述</label>
                                <input type="text" id="metaDescription" placeholder="脚本描述">
                            </div>
                            <div class="metadata-field">
                                <label>@author 作者</label>
                                <input type="text" id="metaAuthor" placeholder="作者名">
                            </div>
                        </div>

                        <!-- 高级功能开关 -->
                        <div class="advanced-toggle">
                            <label class="toggle-switch">
                                <input type="checkbox" id="advancedToggle">
                                <span class="slider"></span>
                            </label>
                            <span class="toggle-label">高级功能(@match、@grant等)</span>
                        </div>

                        <!-- 高级功能区域 -->
                        <div class="advanced-content" id="advancedContent">
                            <div class="metadata-section">
                                <div class="section-header">匹配规则</div>
                                <div class="metadata-field">
                                    <label>@match 匹配规则</label>
                                    <textarea id="metaMatch" placeholder="*://*/*&#10;每行一个规则"></textarea>
                                </div>
                                <div class="metadata-field">
                                    <label>@include 包含规则</label>
                                    <textarea id="metaInclude" placeholder="https://*/*&#10;每行一个规则"></textarea>
                                </div>
                                <div class="metadata-field">
                                    <label>@exclude 排除规则</label>
                                    <textarea id="metaExclude" placeholder="https://*/*&#10;每行一个规则"></textarea>
                                </div>
                            </div>

                            <div class="metadata-section">
                                <div class="section-header">权限设置</div>
                                <div class="metadata-field">
                                    <label>@grant 授权</label>
                                    <textarea id="metaGrant" placeholder="GM_addStyle&#10;GM_xmlhttpRequest&#10;每行一个授权"></textarea>
                                </div>
                                <div class="metadata-field">
                                    <label>@connect 连接</label>
                                    <textarea id="metaConnect" placeholder="api.example.com&#10;每行一个域名"></textarea>
                                </div>
                                <div class="metadata-field">
                                    <label>@require 依赖</label>
                                    <textarea id="metaRequire" placeholder="https://code.jquery.com/jquery-3.6.0.min.js&#10;每行一个URL"></textarea>
                                </div>
                            </div>

                            <div class="metadata-section">
                                <div class="section-header">脚本信息</div>
                                <div class="metadata-field">
                                    <label>@run-at 运行时机</label>
                                    <input type="text" id="metaRunAt" placeholder="document-start / document-end / document-idle">
                                </div>
                                <div class="metadata-field">
                                    <label>@noframes 框架控制</label>
                                    <input type="text" id="metaNoframes" placeholder="输入 @noframes 启用">
                                </div>
                                <div class="metadata-field">
                                    <label>@icon 图标</label>
                                    <input type="text" id="metaIcon" placeholder="https://example.com/icon.png">
                                </div>
                                <div class="metadata-field">
                                    <label>@license 许可证</label>
                                    <input type="text" id="metaLicense" placeholder="MIT / GPL / etc">
                                </div>
                            </div>

                            <div class="metadata-section">
                                <div class="section-header">更新相关</div>
                                <div class="metadata-field">
                                    <label>@downloadURL 下载地址</label>
                                    <input type="text" id="metaDownloadURL" placeholder="https://example.com/script.user.js">
                                </div>
                                <div class="metadata-field">
                                    <label>@updateURL 更新地址</label>
                                    <input type="text" id="metaUpdateURL" placeholder="https://example.com/script.meta.js">
                                </div>
                            </div>

                            <div class="metadata-section">
                                <div class="section-header">其他元数据</div>
                                <div class="metadata-field">
                                    <label>自定义标签</label>
                                    <textarea id="metaOther" placeholder="@homepage https://example.com&#10;@supportURL https://example.com/support&#10;每行一个"></textarea>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 底部功能按钮 - 简化版 -->
                <div class="action-buttons">
                    <button class="execute-btn disabled" id="executeBtn">执行</button>
                    <button class="clear-btn" id="clearBtn">清空</button>
                </div>
            </div>
        </div>
    </div>
    `;

    // 获取所有元素
    const panel = shadow.getElementById('panel');
    const panelContent = shadow.getElementById('panelContent');
    const toggleBtn = shadow.getElementById('togglePanel');
    const dragHandle = shadow.getElementById('dragHandle');
    const fileInput = shadow.getElementById('fileInput');
    const codeEditor = shadow.getElementById('codeEditor');
    const executeBtn = shadow.getElementById('executeBtn');
    const clearBtn = shadow.getElementById('clearBtn');
    const clearTextBtn = shadow.getElementById('clearTextBtn');
    const activeSource = shadow.getElementById('activeSource');
    const sourceText = shadow.getElementById('sourceText');
    const sourceTime = shadow.getElementById('sourceTime');

    // 脚本信息相关
    const infoHeader = shadow.querySelector('.info-header');
    const infoContent = shadow.getElementById('infoContent');
    const infoToggle = shadow.getElementById('infoToggle');

    // 脚本修改相关
    const editHeader = shadow.querySelector('.edit-header');
    const editContent = shadow.getElementById('editContent');
    const editToggle = shadow.getElementById('editToggle');
    const headerStatus = shadow.getElementById('headerStatus');

    // 高级功能相关
    const advancedToggle = shadow.getElementById('advancedToggle');
    const advancedContent = shadow.getElementById('advancedContent');

    // 输入字段
    const metaName = shadow.getElementById('metaName');
    const metaNamespace = shadow.getElementById('metaNamespace');
    const metaVersion = shadow.getElementById('metaVersion');
    const metaDescription = shadow.getElementById('metaDescription');
    const metaAuthor = shadow.getElementById('metaAuthor');
    const metaMatch = shadow.getElementById('metaMatch');
    const metaInclude = shadow.getElementById('metaInclude');
    const metaExclude = shadow.getElementById('metaExclude');
    const metaGrant = shadow.getElementById('metaGrant');
    const metaConnect = shadow.getElementById('metaConnect');
    const metaRequire = shadow.getElementById('metaRequire');
    const metaRunAt = shadow.getElementById('metaRunAt');
    const metaNoframes = shadow.getElementById('metaNoframes');
    const metaIcon = shadow.getElementById('metaIcon');
    const metaLicense = shadow.getElementById('metaLicense');
    const metaDownloadURL = shadow.getElementById('metaDownloadURL');
    const metaUpdateURL = shadow.getElementById('metaUpdateURL');
    const metaOther = shadow.getElementById('metaOther');

    // 拖动功能实现
    let isDragging = false;
    let startX, startY, startLeft, startTop;

    function initDrag() {
        if (!panel || !dragHandle) return;

        dragHandle.addEventListener('mousedown', startDrag);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', stopDrag);
    }

    function startDrag(e) {
        if (e.target === toggleBtn || toggleBtn.contains(e.target)) return;
        if (panel.classList.contains('minimized')) return;

        e.preventDefault();
        isDragging = true;
        panel.classList.add('dragging');

        const rect = panel.getBoundingClientRect();
        startLeft = rect.left;
        startTop = rect.top;
        startX = e.clientX;
        startY = e.clientY;

        panel.style.position = 'fixed';
        panel.style.left = startLeft + 'px';
        panel.style.top = startTop + 'px';
        panel.style.right = 'auto';
        panel.style.bottom = 'auto';
        panel.style.margin = '0';
    }

    function drag(e) {
        if (!isDragging) return;
        e.preventDefault();

        const dx = e.clientX - startX;
        const dy = e.clientY - startY;

        let newLeft = startLeft + dx;
        let newTop = startTop + dy;

        const maxLeft = window.innerWidth - panel.offsetWidth;
        const maxTop = window.innerHeight - panel.offsetHeight;

        newLeft = Math.max(0, Math.min(newLeft, maxLeft));
        newTop = Math.max(0, Math.min(newTop, maxTop));

        panel.style.left = newLeft + 'px';
        panel.style.top = newTop + 'px';
    }

    function stopDrag() {
        if (isDragging) {
            isDragging = false;
            panel.classList.remove('dragging');
        }
    }

    // 确保所有元素都存在
    if (!panel || !panelContent || !toggleBtn || !fileInput || !codeEditor || !executeBtn || !clearBtn) {
        console.error('面板元素初始化失败');
        return;
    }

    // 状态管理
    let hasFile = false;
    let hasText = false;
    let activeSourceType = null;
    let lastOperationTime = null;
    let lastFileName = '';
    let advancedEnabled = false;
    let infoExpanded = false;
    let editExpanded = false;
    let isPanelMinimized = false;
    let currentFileContent = '';
    let originalHeaderContent = '';
    let originalFormState = {};
    let fileType = '';

    // 初始化拖动功能
    initDrag();

    // 从 localStorage 读取面板状态
    function loadPanelState() {
        try {
            const savedState = localStorage.getItem('text2js_panel_minimized');
            if (savedState !== null) {
                isPanelMinimized = savedState === 'true';
                if (isPanelMinimized) {
                    panel.classList.add('minimized');
                    if (panelContent) panelContent.style.display = 'none';
                    if (toggleBtn) toggleBtn.textContent = '+';
                } else {
                    panel.classList.remove('minimized');
                    if (panelContent) panelContent.style.display = 'block';
                    if (toggleBtn) toggleBtn.textContent = '−';
                }
            }
        } catch (e) {
            console.log('无法读取面板状态');
        }
    }

    // 保存面板状态到 localStorage
    function savePanelState() {
        try {
            localStorage.setItem('text2js_panel_minimized', isPanelMinimized);
        } catch (e) {
            console.log('无法保存面板状态');
        }
    }

    // 更新时间显示
    function updateSourceDisplay() {
        if (!sourceText || !activeSource || !sourceTime) return;

        if (activeSourceType === 'file') {
            sourceText.textContent = `文件 ${lastFileName || '已选择文件'}`;
            activeSource.style.background = '#e3f2fd';
            activeSource.style.borderBottomColor = '#bbdefb';
        } else if (activeSourceType === 'text') {
            sourceText.textContent = '文本 粘贴的代码';
            activeSource.style.background = '#fff3e0';
            activeSource.style.borderBottomColor = '#ffe0b2';
        } else {
            sourceText.textContent = '未选择内容';
            activeSource.style.background = '#f5f5f5';
            activeSource.style.borderBottomColor = '#e0e0e0';
        }

        if (lastOperationTime) {
            sourceTime.textContent = `最后操作 ${lastOperationTime}`;
        } else {
            sourceTime.textContent = '';
        }
    }

    // 脚本信息展开/折叠
    if (infoHeader && infoContent && infoToggle) {
        infoHeader.onclick = (e) => {
            e.stopPropagation();
            if (infoExpanded) {
                infoContent.style.display = 'none';
                infoToggle.textContent = '展开';
                infoExpanded = false;
            } else {
                infoContent.style.display = 'block';
                infoToggle.textContent = '收起';
                infoExpanded = true;
            }
        };
    }

    // 脚本修改展开/折叠
    if (editHeader && editContent && editToggle) {
        editHeader.onclick = (e) => {
            e.stopPropagation();
            if (editExpanded) {
                editContent.style.display = 'none';
                editToggle.textContent = '展开';
                editExpanded = false;
            } else {
                editContent.style.display = 'block';
                editToggle.textContent = '收起';
                editExpanded = true;
            }
        };
    }

    // 高级功能开关
    if (advancedToggle && advancedContent) {
        advancedToggle.onchange = (e) => {
            advancedEnabled = e.target.checked;
            advancedContent.style.display = advancedEnabled ? 'block' : 'none';
            updateExecuteButtonState();
        };
    }

    // 保存原始表单状态
    function saveOriginalFormState() {
        originalFormState = {
            metaName: metaName?.value || '',
            metaNamespace: metaNamespace?.value || '',
            metaVersion: metaVersion?.value || '',
            metaDescription: metaDescription?.value || '',
            metaAuthor: metaAuthor?.value || '',
            metaMatch: metaMatch?.value || '',
            metaInclude: metaInclude?.value || '',
            metaExclude: metaExclude?.value || '',
            metaGrant: metaGrant?.value || '',
            metaConnect: metaConnect?.value || '',
            metaRequire: metaRequire?.value || '',
            metaRunAt: metaRunAt?.value || '',
            metaNoframes: metaNoframes?.value || '',
            metaIcon: metaIcon?.value || '',
            metaLicense: metaLicense?.value || '',
            metaDownloadURL: metaDownloadURL?.value || '',
            metaUpdateURL: metaUpdateURL?.value || '',
            metaOther: metaOther?.value || '',
            advancedEnabled: advancedEnabled
        };
    }

    // 检查表单是否被修改
    function isFormModified() {
        if (!activeSourceType) return false;

        return (metaName?.value || '') !== originalFormState.metaName ||
               (metaNamespace?.value || '') !== originalFormState.metaNamespace ||
               (metaVersion?.value || '') !== originalFormState.metaVersion ||
               (metaDescription?.value || '') !== originalFormState.metaDescription ||
               (metaAuthor?.value || '') !== originalFormState.metaAuthor ||
               (metaMatch?.value || '') !== originalFormState.metaMatch ||
               (metaInclude?.value || '') !== originalFormState.metaInclude ||
               (metaExclude?.value || '') !== originalFormState.metaExclude ||
               (metaGrant?.value || '') !== originalFormState.metaGrant ||
               (metaConnect?.value || '') !== originalFormState.metaConnect ||
               (metaRequire?.value || '') !== originalFormState.metaRequire ||
               (metaRunAt?.value || '') !== originalFormState.metaRunAt ||
               (metaNoframes?.value || '') !== originalFormState.metaNoframes ||
               (metaIcon?.value || '') !== originalFormState.metaIcon ||
               (metaLicense?.value || '') !== originalFormState.metaLicense ||
               (metaDownloadURL?.value || '') !== originalFormState.metaDownloadURL ||
               (metaUpdateURL?.value || '') !== originalFormState.metaUpdateURL ||
               (metaOther?.value || '') !== originalFormState.metaOther ||
               advancedEnabled !== originalFormState.advancedEnabled;
    }

    // 获取当前活动的内容
    function getActiveContent() {
        if (activeSourceType === 'file') {
            return currentFileContent;
        } else if (activeSourceType === 'text') {
            return codeEditor?.value || '';
        }
        return null;
    }

    // 检查是否有内容可执行
    function hasContent() {
        return activeSourceType !== null && getActiveContent() && getActiveContent().length > 0;
    }

    // 更新执行按钮状态
    function updateExecuteButtonState() {
        if (!executeBtn) return;

        if (hasContent()) {
            executeBtn.classList.remove('disabled');
            executeBtn.disabled = false;
        } else {
            executeBtn.classList.add('disabled');
            executeBtn.disabled = true;
        }
    }

    // 从代码中解析元数据
    function parseCodeToForm(code) {
        if (!code) return;

        let processed = code
            .replace(/\r\n/g,'\n')
            .replace(/[\uFEFF]/g,'')
            .replace(/,/g,',')
            .replace(/;/g,';')
            .replace(/:/g,':')
            .replace(/[""]/g,'"')
            .replace(/['']/g,"'");

        let headerMatch = processed.match(/\/\/\s*==UserScript==([\s\S]*?)\/\/\s*==\/UserScript==/);
        if (headerMatch && headerStatus) {
            headerStatus.textContent = '已检测';
            headerStatus.className = 'status-badge';

            originalHeaderContent = headerMatch[0];
            let header = headerMatch[1];

            // 清空所有字段
            [metaName, metaNamespace, metaVersion, metaDescription, metaAuthor,
             metaMatch, metaInclude, metaExclude, metaGrant, metaConnect,
             metaRequire, metaRunAt, metaNoframes, metaIcon, metaLicense,
             metaDownloadURL, metaUpdateURL, metaOther].forEach(field => {
                if (field) field.value = '';
            });

            const lines = header.split('\n');
            const matchLines = [];
            const includeLines = [];
            const excludeLines = [];
            const grantLines = [];
            const connectLines = [];
            const requireLines = [];
            const otherLines = [];

            lines.forEach(line => {
                line = line.trim();
                if (!line) return;

                let match = line.match(/^\/\/\s*@(\w+)\s+(.*)$/);
                if (match) {
                    let tag = match[1];
                    let value = match[2].trim();

                    switch(tag) {
                        case 'name':
                            if (metaName) metaName.value = value;
                            detectedName = value;
                            break;
                        case 'namespace':
                            if (metaNamespace) metaNamespace.value = value;
                            break;
                        case 'version':
                            if (metaVersion) metaVersion.value = value;
                            detectedVersion = value;
                            break;
                        case 'description':
                            if (metaDescription) metaDescription.value = value;
                            break;
                        case 'author':
                            if (metaAuthor) metaAuthor.value = value;
                            break;
                        case 'match':
                            if (value) matchLines.push(value);
                            break;
                        case 'include':
                            if (value) includeLines.push(value);
                            break;
                        case 'exclude':
                            if (value) excludeLines.push(value);
                            break;
                        case 'grant':
                            if (value) grantLines.push(value);
                            break;
                        case 'connect':
                            if (value) connectLines.push(value);
                            break;
                        case 'require':
                            if (value) requireLines.push(value);
                            break;
                        case 'run-at':
                            if (metaRunAt) metaRunAt.value = value;
                            break;
                        case 'noframes':
                            if (metaNoframes) metaNoframes.value = '@noframes';
                            break;
                        case 'icon':
                            if (metaIcon) metaIcon.value = value;
                            break;
                        case 'license':
                            if (metaLicense) metaLicense.value = value;
                            break;
                        case 'downloadURL':
                            if (metaDownloadURL) metaDownloadURL.value = value;
                            break;
                        case 'updateURL':
                            if (metaUpdateURL) metaUpdateURL.value = value;
                            break;
                        default:
                            otherLines.push(line);
                    }
                } else {
                    if (line.startsWith('//') && !line.includes('==UserScript==')) {
                        otherLines.push(line);
                    }
                }
            });

            if (metaMatch) metaMatch.value = matchLines.join('\n');
            if (metaInclude) metaInclude.value = includeLines.join('\n');
            if (metaExclude) metaExclude.value = excludeLines.join('\n');
            if (metaGrant) metaGrant.value = grantLines.join('\n');
            if (metaConnect) metaConnect.value = connectLines.join('\n');
            if (metaRequire) metaRequire.value = requireLines.join('\n');
            if (metaOther) metaOther.value = otherLines.join('\n');

        } else if (headerStatus) {
            headerStatus.textContent = '未检测';
            headerStatus.className = 'status-badge na';
            originalHeaderContent = '';

            if (activeSourceType === 'file') {
                detectedName = lastFileName.replace(/\.(txt|js)$/,'');
            } else {
                detectedName = 'pasted_code';
            }
            detectedVersion = '1.0';

            if (metaName) metaName.value = detectedName;
            if (metaVersion) metaVersion.value = '1.0';
            if (metaNamespace) metaNamespace.value = 'http://tampermonkey.net/';
        }
    }

    // 从表单生成完整的头部
    function generateHeaderFromForm() {
        let header = '// ==UserScript==\n';

        if (metaName?.value) {
            header += `// @name         ${metaName.value}\n`;
            detectedName = metaName.value;
        }
        if (metaNamespace?.value) header += `// @namespace    ${metaNamespace.value}\n`;
        if (metaVersion?.value) {
            header += `// @version      ${metaVersion.value}\n`;
            detectedVersion = metaVersion.value;
        }
        if (metaDescription?.value) header += `// @description  ${metaDescription.value}\n`;
        if (metaAuthor?.value) header += `// @author       ${metaAuthor.value}\n`;

        if (metaMatch?.value) {
            metaMatch.value.split('\n').forEach(line => {
                if (line.trim()) header += `// @match        ${line.trim()}\n`;
            });
        }

        if (metaInclude?.value) {
            metaInclude.value.split('\n').forEach(line => {
                if (line.trim()) header += `// @include      ${line.trim()}\n`;
            });
        }

        if (metaExclude?.value) {
            metaExclude.value.split('\n').forEach(line => {
                if (line.trim()) header += `// @exclude      ${line.trim()}\n`;
            });
        }

        if (metaGrant?.value) {
            metaGrant.value.split('\n').forEach(line => {
                if (line.trim()) header += `// @grant        ${line.trim()}\n`;
            });
        }

        if (metaConnect?.value) {
            metaConnect.value.split('\n').forEach(line => {
                if (line.trim()) header += `// @connect      ${line.trim()}\n`;
            });
        }

        if (metaRequire?.value) {
            metaRequire.value.split('\n').forEach(line => {
                if (line.trim()) header += `// @require      ${line.trim()}\n`;
            });
        }

        if (metaRunAt?.value) {
            header += `// @run-at       ${metaRunAt.value}\n`;
        }

        if (metaNoframes?.value) {
            header += `// @noframes\n`;
        }

        if (metaIcon?.value) {
            header += `// @icon         ${metaIcon.value}\n`;
        }

        if (metaLicense?.value) {
            header += `// @license      ${metaLicense.value}\n`;
        }

        if (metaDownloadURL?.value) {
            header += `// @downloadURL  ${metaDownloadURL.value}\n`;
        }

        if (metaUpdateURL?.value) {
            header += `// @updateURL    ${metaUpdateURL.value}\n`;
        }

        if (metaOther?.value) {
            metaOther.value.split('\n').forEach(line => {
                if (line.trim()) header += `// ${line.trim()}\n`;
            });
        }

        let hasMatchRule = (metaMatch?.value && metaMatch.value.trim()) || header.includes('@match');
        if (!hasMatchRule) {
            header += `// @match        *://*/*\n`;
        }

        header += '// ==/UserScript==\n\n';
        return header;
    }

    // 处理代码
    function processCode(content) {
        if (!content) return null;

        let processed = content
            .replace(/\r\n/g,'\n')
            .replace(/[\uFEFF]/g,'')
            .replace(/,/g,',')
            .replace(/;/g,';')
            .replace(/:/g,':')
            .replace(/[""]/g,'"')
            .replace(/['']/g,"'");

        const newHeader = generateHeaderFromForm();

        let headerMatch = processed.match(/\/\/\s*==UserScript==[\s\S]*?\/\/\s*==\/UserScript==/);

        if (headerMatch) {
            return processed.replace(headerMatch[0], newHeader.trim());
        } else {
            return newHeader + processed;
        }
    }

    // 下载文件
    function downloadFile(content) {
        const safeName = (detectedName || 'script').replace(/[\\/:*?"<>|]/g,'');
        const versionNum = detectedVersion || '1.0';
        const finalName = `${safeName}_v${versionNum}.js`;

        const blob = new Blob([content], { type:'text/javascript;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = finalName;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    // 清空所有内容
    function clearAll() {
        if (fileInput) fileInput.value = '';
        if (codeEditor) codeEditor.value = '';
        currentFileContent = '';
        lastFileName = '';
        hasFile = false;
        hasText = false;
        activeSourceType = null;
        lastOperationTime = null;
        fileType = '';

        detectedName = '';
        detectedVersion = '';
        originalHeaderContent = '';

        if (headerStatus) {
            headerStatus.textContent = '未检测';
            headerStatus.className = 'status-badge na';
        }

        [metaName, metaNamespace, metaVersion, metaDescription, metaAuthor,
         metaMatch, metaInclude, metaExclude, metaGrant, metaConnect,
         metaRequire, metaRunAt, metaNoframes, metaIcon, metaLicense,
         metaDownloadURL, metaUpdateURL, metaOther].forEach(field => {
            if (field) field.value = '';
        });

        saveOriginalFormState();
        updateSourceDisplay();
        updateExecuteButtonState();
    }

    // 执行按钮点击
    if (executeBtn) {
        executeBtn.onclick = (e) => {
            e.stopPropagation();

            if (!hasContent()) return;

            const content = getActiveContent();
            const processedCode = processCode(content);

            if (processedCode) {
                downloadFile(processedCode);

                if (activeSourceType === 'file') {
                    currentFileContent = processedCode;
                } else if (activeSourceType === 'text' && codeEditor) {
                    codeEditor.value = processedCode;
                }

                parseCodeToForm(processedCode);
                saveOriginalFormState();
            }

            executeBtn.style.transform = 'scale(0.95)';
            setTimeout(() => { executeBtn.style.transform = 'scale(1)'; }, 120);
        };
    }

    // 清空按钮点击
    if (clearBtn) {
        clearBtn.onclick = (e) => {
            e.stopPropagation();
            clearAll();

            clearBtn.style.transform = 'scale(0.95)';
            setTimeout(() => { clearBtn.style.transform = 'scale(1)'; }, 120);
        };
    }

    // 清空文本按钮点击
    if (clearTextBtn) {
        clearTextBtn.onclick = (e) => {
            e.stopPropagation();
            if (codeEditor) codeEditor.value = '';
            hasText = false;

            if (activeSourceType === 'text') {
                activeSourceType = hasFile ? 'file' : null;
                if (activeSourceType === 'file') {
                    parseCodeToForm(currentFileContent);
                    lastOperationTime = new Date().toLocaleTimeString();
                } else {
                    clearAll();
                    return;
                }
            }

            updateSourceDisplay();
            saveOriginalFormState();
            updateExecuteButtonState();
        };
    }

    // 文本编辑框输入
    if (codeEditor) {
        codeEditor.addEventListener('input', (e) => {
            const value = e.target.value;
            hasText = value.length > 0;

            if (hasText) {
                activeSourceType = 'text';
                lastOperationTime = new Date().toLocaleTimeString();
                parseCodeToForm(value);
            } else {
                hasText = false;
                if (hasFile) {
                    activeSourceType = 'file';
                    parseCodeToForm(currentFileContent);
                    lastOperationTime = new Date().toLocaleTimeString();
                } else {
                    activeSourceType = null;
                    lastOperationTime = null;
                    clearAll();
                    return;
                }
            }

            updateSourceDisplay();
            saveOriginalFormState();
            updateExecuteButtonState();
        });
    }

    // 面板折叠
    if (toggleBtn && panel && panelContent) {
        toggleBtn.onclick = (e) => {
            e.stopPropagation();
            if (isPanelMinimized) {
                panel.classList.remove('minimized');
                panelContent.style.display = 'block';
                toggleBtn.textContent = '−';
                isPanelMinimized = false;

                panel.style.left = '';
                panel.style.top = '';
                panel.style.right = '20px';
                panel.style.bottom = 'auto';
            } else {
                panel.classList.add('minimized');
                panelContent.style.display = 'none';
                toggleBtn.textContent = '+';
                isPanelMinimized = true;
            }
            savePanelState();
        };

        panel.onclick = (e) => {
            if (isPanelMinimized && e.target === panel) {
                panel.classList.remove('minimized');
                panelContent.style.display = 'block';
                toggleBtn.textContent = '−';
                isPanelMinimized = false;
                savePanelState();
            }
        };
    }

    // 文件选择
    if (fileInput) {
        fileInput.onchange = e => {
            const file = e.target.files[0];
            if (!file) return;

            lastFileName = file.name;
            fileType = file.name.split('.').pop().toLowerCase();

            const reader = new FileReader();
            reader.onload = evt => {
                currentFileContent = evt.target.result;
                hasFile = true;
                activeSourceType = 'file';
                lastOperationTime = new Date().toLocaleTimeString();

                if (codeEditor) codeEditor.value = '';
                hasText = false;

                parseCodeToForm(currentFileContent);
                saveOriginalFormState();

                if (fileInput) fileInput.title = detectedName;
                updateSourceDisplay();
                updateExecuteButtonState();
            };

            reader.readAsText(file, 'utf-8');
        };
    }

    // 初始化状态
    loadPanelState();
    updateExecuteButtonState();
    updateSourceDisplay();

    if (infoContent) infoContent.style.display = 'none';
    if (infoToggle) infoToggle.textContent = '展开';
    if (editContent) editContent.style.display = 'none';
    if (editToggle) editToggle.textContent = '展开';
    if (advancedContent) advancedContent.style.display = 'none';

    saveOriginalFormState();
})();