TriX Core Library

Core logic library for TriX Executor with Python/WASM support.

Versão de: 04/07/2025. Veja: a última versão.

Este script não deve ser instalado diretamente. Este script é uma biblioteca de outros scripts para incluir com o diretório meta // @require https://updategf.qytechs.cn/scripts/541461/1618711/TriX%20Core%20Library.js

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name        TriX Core Library
// @namespace   https://github.com/YourUsername/TriX-Executor
// @version     1.6.4
// @description Core logic library for TriX Executor with Python/WASM support.
// @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 = 'https://cdn.jsdelivr.net/pyodide/v0.25.1/full/pyodide.js';

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

        loadPyodideDynamically() {
            return new Promise((resolve, reject) => {
                if (window.loadPyodide) return resolve(window.loadPyodide);
                const script = document.createElement('script');
                script.src = PYODIDE_CDN;
                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);
            });
        },

        // This is now called proactively when the UI is first opened.
        async init() {
            if (this.pyodide || this.isLoading) return;
            this.isLoading = true;
            
            TriX_UI.setPythonStatus('loading');
            TriX_UI.log('Initializing Python runtime (Pyodide)... This is a large one-time download.', 'info');
            
            try {
                const loadPyodideFunction = await this.loadPyodideDynamically();
                this.pyodide = await loadPyodideFunction();
                TriX_UI.log('Python runtime ready.', 'info');
                TriX_UI.setPythonStatus('ready');
            } catch (err) {
                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');
                 // Re-check in case it finished loading while the user clicked
                 if(this.isLoading) return;
                 await this.init(); // Attempt to init again
                 if (!this.pyodide) return;
            }
            TriX_UI.setPythonStatus('running');
            try {
                if (packages) {
                    TriX_UI.log(`Loading Python packages: ${packages}`, 'info');
                    await this.pyodide.loadPackage("micropip");
                    const micropip = this.pyodide.pyimport("micropip");
                    await micropip.install(packages.split(',').map(p => p.trim()));
                    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');
            }
        }
    };
    
    const TabManager = {
        tabs:[], myTabInfo:{}, uiInitialized:false, isMaster:false,
        init(username){this.myTabInfo={id:TAB_ID,username:username,loadTime:LOAD_TIME,lastSeen:Date.now()};GM_addValueChangeListener(TAB_LIST_KEY,(name,old_value,new_value,remote)=>{if(remote)this.pruneAndRefresh(new_value)});this.register();setInterval(()=>this.register(),HEARTBEAT_INTERVAL);window.addEventListener('beforeunload',()=>this.unregister())},
        async register(){let currentTabs=await GM_getValue(TAB_LIST_KEY,[]);const now=Date.now();currentTabs=currentTabs.filter(tab=>now-tab.lastSeen<STALE_TAB_TIMEOUT);this.myTabInfo.lastSeen=now;const myIndex=currentTabs.findIndex(tab=>tab.id===TAB_ID);if(myIndex>-1){currentTabs[myIndex]=this.myTabInfo}else{currentTabs.push(this.myTabInfo)}await GM_setValue(TAB_LIST_KEY,currentTabs);this.pruneAndRefresh(currentTabs)},
        async unregister(){let currentTabs=await GM_getValue(TAB_LIST_KEY,[]);currentTabs=currentTabs.filter(tab=>tab.id!==TAB_ID);await GM_setValue(TAB_LIST_KEY,currentTabs)},
        pruneAndRefresh(tabList){this.tabs=tabList;if(this.uiInitialized&&typeof TriX_UI!=='undefined')TriX_UI.updateTabCountUI(tabList.length);this.checkMasterStatus()},
        checkMasterStatus(){this.isMaster=this.amIMaster();if(this.isMaster&&!this.uiInitialized){this.initUI()}},
        amIMaster(){if(!this.myTabInfo.username||this.myTabInfo.username.startsWith('Guest_'))return true;const competingTabs=this.tabs.filter(tab=>tab.username===this.myTabInfo.username);if(competingTabs.length===0)return true;const earliestLoadTime=Math.min(...competingTabs.map(tab=>tab.loadTime));return this.myTabInfo.loadTime===earliestLoadTime},
        initUI(){if(this.uiInitialized)return;console.log('[TriX Core] This tab is the master. Initializing UI.');this.uiInitialized=true;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,""),s=e.replace(SCRIPT_PREFIX,"");document.getElementById("trix-editor").value=t,document.getElementById("trix-save-name").value=s,TriX_UI.log(`Loaded script: ${s}`,"info"),TriX_UI.currentScriptName=s,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 s=(await GM_listValues()).filter(e=>e.startsWith(SCRIPT_PREFIX));s.sort().forEach(e=>{const s=document.createElement("div");s.className="trix-script-item",s.textContent=e.replace(SCRIPT_PREFIX,""),s.dataset.scriptKey=e,t.appendChild(s)}),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 };
})();