TriX Core Library

Core logic library for the TriX Executor. Not intended for direct installation.

Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyforks.org/scripts/541461/1618726/TriX%20Core%20Library.js

// ==UserScript==
// @name        TriX Core Library
// @namespace   https://github.com/YourUsername/TriX-Executor
// @version     1.6.5
// @description Core logic library for TriX Executor with Python/WASM support and progress feedback.
// @author      You
// @license     MIT
// ==/UserScript==

const TriX_Core = (function() {
    'use strict';
    const SCRIPT_PREFIX = 'trix_script_';
    const BROADCAST_CHANNEL = 'trix_broadcast_channel';
    const TAB_LIST_KEY = 'trix_active_tabs';
    const HEARTBEAT_INTERVAL = 5000;
    const STALE_TAB_TIMEOUT = 15000;
    const TAB_ID = `tab_${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`;
    const LOAD_TIME = Date.now();
    const PYODIDE_CDN_BASE = 'https://cdn.jsdelivr.net/pyodide/v0.25.1/full/';

    const PyodideManager = {
        pyodide: null,
        isLoading: false,

        loadPyodideDynamically() {
            // No changes needed here, the previous version is correct.
            return new Promise((resolve, reject) => {
                if (window.loadPyodide) return resolve(window.loadPyodide);
                const script = document.createElement('script');
                script.src = `${PYODIDE_CDN_BASE}pyodide.js`;
                script.onload = () => {
                    const checkInterval = setInterval(() => {
                        if (window.loadPyodide) {
                            clearInterval(checkInterval);
                            resolve(window.loadPyodide);
                        }
                    }, 100);
                };
                script.onerror = (err) => reject(new Error("Failed to load Pyodide script from CDN. Check browser console for network errors."));
                document.head.appendChild(script);
            });
        },
        
        // --- NEW: Enhanced init function with progress bar ---
        async init() {
            if (this.pyodide || this.isLoading) return;
            this.isLoading = true;
            
            TriX_UI.setPythonStatus('loading');
            TriX_UI.log('Initializing Python runtime (Pyodide)...', 'info');
            TriX_UI.log('Note: First-time setup is a large download (~35MB). It will be cached for future use.', 'warn');

            // Create and append the progress bar element to the console
            const progressElement = TriX_UI.createProgressBar();

            try {
                const loadPyodideFunction = await this.loadPyodideDynamically();
                
                this.pyodide = await loadPyodideFunction({
                    indexURL: PYODIDE_CDN_BASE,
                    // This hook provides live updates on the loading process
                    loadPackageMessageCallback: (message) => {
                        const progressText = document.getElementById('trix-py-progress-text');
                        if (progressText) {
                            progressText.textContent = `Loading: ${message}`;
                        }
                    }
                });

                progressElement.remove(); // Remove progress bar on success
                TriX_UI.log('Python runtime ready.', 'info');
                TriX_UI.setPythonStatus('ready');
            } catch (err) {
                if(progressElement) progressElement.remove();
                TriX_UI.setPythonStatus('error');
                TriX_UI.log(`Error loading Pyodide: ${err.message}. Python features will be unavailable.`, 'error');
                console.error("Pyodide loading error:", err);
            } finally {
                this.isLoading = false;
            }
        },

        async run(code, packages) {
            if (!this.pyodide) {
                 TriX_UI.log('Python runtime is not ready yet. Please wait.', 'warn');
                 if(this.isLoading) return;
                 await this.init();
                 if (!this.pyodide) return;
            }
            TriX_UI.setPythonStatus('running');
            try {
                if (packages) {
                    const packageList = packages.split(',').map(p => p.trim()).filter(p => p);
                    TriX_UI.log(`Loading Python packages: ${packageList.join(', ')}`, 'info');
                    await this.pyodide.loadPackage("micropip");
                    const micropip = this.pyodide.pyimport("micropip");
                    await micropip.install(packageList);
                    TriX_UI.log('Packages loaded.', 'info');
                }
                TriX_UI.log('Executing Python script...', 'info');
                this.pyodide.setStdout({ batched: (msg) => TriX_UI.log(`${msg}`, 'log') });
                this.pyodide.setStderr({ batched: (msg) => TriX_UI.log(`[Python Error]: ${msg}`, 'error') });
                await this.pyodide.runPythonAsync(code);
            } catch (err) {
                TriX_UI.log(`Python Error: ${err}`, 'error');
            } finally {
                TriX_UI.setPythonStatus('ready');
            }
        }
    };
    
    // --- The rest of the library is unchanged and minified for brevity ---
    const TabManager={tabs:[],myTabInfo:{},uiInitialized:!1,isMaster:!1,init(e){this.myTabInfo={id:TAB_ID,username:e,loadTime:LOAD_TIME,lastSeen:Date.now()},GM_addValueChangeListener(TAB_LIST_KEY,(e,t,i,s)=>{s&&this.pruneAndRefresh(i)}),this.register(),setInterval(()=>this.register(),5e3),window.addEventListener("beforeunload",()=>this.unregister())},async register(){let e=await GM_getValue(TAB_LIST_KEY,[]);const t=Date.now();e=e.filter(e=>t-e.lastSeen<15e3),this.myTabInfo.lastSeen=t;const i=e.findIndex(e=>e.id===TAB_ID);-1<i?e[i]=this.myTabInfo:e.push(this.myTabInfo),await GM_setValue(TAB_LIST_KEY,e),this.pruneAndRefresh(e)},async unregister(){let e=await GM_getValue(TAB_LIST_KEY,[]);e=e.filter(e=>e.id!==TAB_ID),await GM_setValue(TAB_LIST_KEY,e)},pruneAndRefresh(e){this.tabs=e,this.uiInitialized&&"undefined"!=typeof TriX_UI&&TriX_UI.updateTabCountUI(e.length),this.checkMasterStatus()},checkMasterStatus(){this.isMaster=this.amIMaster(),this.isMaster&&!this.uiInitialized&&this.initUI()},amIMaster(){if(!this.myTabInfo.username||this.myTabInfo.username.startsWith("Guest_"))return!0;const e=this.tabs.filter(e=>e.username===this.myTabInfo.username);return 0===e.length||this.myTabInfo.loadTime===Math.min(...e.map(e=>e.loadTime))},initUI(){this.uiInitialized||(console.log("[TriX Core] This tab is the master. Initializing UI."),this.uiInitialized=!0,TriX_UI.init(),MultiTab.init())}};
    const ScriptManager={async saveScriptFromEditor(){const e=document.getElementById("trix-save-name").value.trim(),t=document.getElementById("trix-editor").value;e?t?(await GM_setValue(SCRIPT_PREFIX+e,t),TriX_UI.log(`Script '${e}' saved.`,"info"),this.populateScriptList(SCRIPT_PREFIX+e)):TriX_UI.log("Cannot save: Editor is empty.","warn"):TriX_UI.log("Cannot save: Name is required.","error")},async loadScriptToEditor(e){if(!e)return TriX_UI.log("Invalid script key.","error");const t=await GM_getValue(e,""),i=e.replace(SCRIPT_PREFIX,"");document.getElementById("trix-editor").value=t,document.getElementById("trix-save-name").value=i,TriX_UI.log(`Loaded script: ${i}`,"info"),TriX_UI.currentScriptName=i,TriX_UI.setActiveScriptItem(e)},async deleteCurrentScript(){const e=TriX_UI.currentScriptName;e&&confirm(`Are you sure you want to delete '${e}'?`)&&(await GM_deleteValue(SCRIPT_PREFIX+e),TriX_UI.log(`Script '${e}' deleted.`,"info"),document.getElementById("trix-editor").value="",document.getElementById("trix-save-name").value="",TriX_UI.currentScriptName="",this.populateScriptList())},async populateScriptList(e=null){const t=document.getElementById("trix-script-list");t.innerHTML="";const i=(await GM_listValues()).filter(e=>e.startsWith(SCRIPT_PREFIX));i.sort().forEach(e=>{const i=document.createElement("div");i.className="trix-script-item",i.textContent=e.replace(SCRIPT_PREFIX,""),i.dataset.scriptKey=e,t.appendChild(i)}),TriX_UI.setActiveScriptItem(e||TriX_UI.currentScriptName?SCRIPT_PREFIX+TriX_UI.currentScriptName:null)}};
    const Executor={execute(e){if(!e.trim())return TriX_UI.log("Execution skipped: script is empty.","warn");TriX_UI.log("Executing script...","info");try{const t=this.createAPI(),i=new Function("TriX",e);i(t)}catch(e){TriX_UI.log(`Execution Error: ${e.message}`,"error"),console.error("TriX Executor Error:",e)}},createAPI:()=>({log:(e,t="log")=>{const i="object"==typeof e?JSON.stringify(e):String(e);TriX_UI.log(i,t)},broadcast:e=>{MultiTab.broadcast(e)},query:(e,t="text")=>{const i=document.querySelector(e);return i?"html"===t?i.innerHTML:"value"===t?i.value:"element"===t?i:i.textContent:null},queryAll:(e,t="text")=>{const i=document.querySelectorAll(e);return Array.from(i).map(e=>"html"===t?e.innerHTML:"value"===t?e.value:"element"===t?e:e.textContent)},GM_addStyle:GM_addStyle,html2canvas:"undefined"!=typeof html2canvas?html2canvas:null})};
    const MultiTab={init(){GM_addValueChangeListener(BROADCAST_CHANNEL,this.listener)},listener(e,t,i,s){s&&i.senderId!==TAB_ID&&TriX_UI.log(`Received broadcast: ${JSON.stringify(i.payload)}`,"broadcast")},broadcast(e){const t={senderId:TAB_ID,timestamp:Date.now(),payload:e};GM_setValue(BROADCAST_CHANNEL,t),TriX_UI.log(`Broadcast sent: ${JSON.stringify(e)}`,"broadcast")}};
    
    return { TabManager, ScriptManager, Executor, MultiTab, PyodideManager };
})();
长期地址
遇到问题?请前往 GitHub 提 Issues。