TriX Core Library

Core logic library for TriX Executor.

当前为 2025-07-11 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/541461/1622888/TriX%20Core%20Library.js

// ==UserScript==
// @name        TriX Core Library
// @namespace   https://github.com/YourUsername/TriX-Executor
// @version     2.3.2
// @description Core logic library for TriX Executor.
// @author      You
// @license     MIT
// ==/UserScript==

const TriX_Core = (function() {
    'use strict';
    
    let _GM; // Internal storage for GM functions

    const TabManager = {
        tabs:[], myTabInfo:{}, uiInitialized:false, isMaster:false,
        init(username, gmFunctions){
            _GM = gmFunctions;
            const TAB_ID = `tab_${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`;
            const LOAD_TIME = Date.now();
            this.myTabInfo={id:TAB_ID,username:username,loadTime:LOAD_TIME,lastSeen:Date.now()};
            
            _GM.GM_addValueChangeListener('trix_active_tabs',(name,old_value,new_value,remote)=>{
                if(remote) this.pruneAndRefresh(new_value);
            });
            
            this.register();
            setInterval(()=>this.register(), 5000);
            window.addEventListener('beforeunload',()=>this.unregister());
        },
        async register(){
            let e = await _GM.GM_getValue("trix_active_tabs", []);
            const t = Date.now();
            e = e.filter(e => t - e.lastSeen < 15000);
            this.myTabInfo.lastSeen = t;
            const i = e.findIndex(e => e.id === this.myTabInfo.id);
            -1 < i ? e[i] = this.myTabInfo : e.push(this.myTabInfo);
            await _GM.GM_setValue("trix_active_tabs", e);
            this.pruneAndRefresh(e);
        },
        async unregister(){
            let e = await _GM.GM_getValue("trix_active_tabs", []);
            e = e.filter(e => e.id !== this.myTabInfo.id);
            await _GM.GM_setValue("trix_active_tabs", e);
        },
        pruneAndRefresh(e){
            this.tabs = e;
            if(this.uiInitialized) TriX_UI.updateTabCountUI(e.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 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(){
            if(this.uiInitialized) return;
            console.log("[TriX Core] This tab is the master. Initializing UI.");
            this.uiInitialized=true;
            TriX_UI.init(_GM);
        }
    };
    
    const ScriptManager = {
        async saveScriptFromEditor() {
            const name = document.getElementById("trix-save-name").value.trim();
            const jsCode = document.getElementById("trix-editor").value;
            const pyCode = document.getElementById("trix-python-editor").value;
            if (!name) return TriX_UI.log("Cannot save: Name is required.", "error");
            if (!jsCode && !pyCode) return TriX_UI.log("Cannot save: Editor is empty.", "warn");
            
            const scriptData = JSON.stringify({ js: jsCode, py: pyCode });
            await _GM.GM_setValue(`trix_script_${name}`, scriptData);
            
            TriX_UI.log(`Script '${name}' saved.`, "info");
            this.populateScriptList();
        },
        async loadScriptToEditor(key) {
            if (!key) return TriX_UI.log("Invalid script key.", "error");
            const scriptJSON = await _GM.GM_getValue(key, "{}");
            const name = key.replace("trix_script_", "");
            try {
                const scriptData = JSON.parse(scriptJSON);
                document.getElementById("trix-editor").value = scriptData.js || "";
                document.getElementById("trix-python-editor").value = scriptData.py || "";
                document.getElementById("trix-save-name").value = name;
                TriX_UI.log(`Loaded script: ${name}`, "info");
                TriX_UI.currentScriptName = name;
                TriX_UI.setActiveScriptItem(key);
            } catch (e) {
                TriX_UI.log("Error loading script data. It might be in an old format.", "error");
            }
        },
        async deleteCurrentScript() {
            const name = TriX_UI.currentScriptName;
            if (name && confirm(`Are you sure you want to delete '${name}'?`)) {
                await _GM.GM_deleteValue(`trix_script_${name}`);
                TriX_UI.log(`Script '${name}' deleted.`, "info");
                document.getElementById("trix-editor").value = "";
                document.getElementById("trix-python-editor").value = "";
                document.getElementById("trix-save-name").value = "";
                TriX_UI.currentScriptName = "";
                this.populateScriptList();
            }
        },
        async populateScriptList() {
            const listEl = document.getElementById("trix-script-list");
            listEl.innerHTML = "";
            const keys = (await _GM.GM_listValues()).filter(e => e.startsWith("trix_script_"));
            keys.sort().forEach(key => {
                const item = document.createElement("div");
                item.className = "trix-script-item";
                item.textContent = key.replace("trix_script_", "");
                item.dataset.scriptKey = key;
                listEl.appendChild(item);
            });
            TriX_UI.setActiveScriptItem(TriX_UI.currentScriptName ? `trix_script_${TriX_UI.currentScriptName}` : null);
        }
    };

    const Executor = {
        executeJS(code) {
            if (!code.trim()) return TriX_UI.log("JS Execution skipped: script is empty.", "warn");
            TriX_UI.log("Executing JavaScript...", "info");
            try {
                const api = this.createAPI();
                new Function("TriX", code)(api);
            } catch (e) {
                TriX_UI.log(`JavaScript Error: ${e.message}`, "error");
            }
        },
        executePY(code) {
            if (!code.trim()) return TriX_UI.log("Python Execution skipped: script is empty.", "warn");
            if (typeof Sk === 'undefined') return TriX_UI.log("Skulpt not loaded. Cannot run Python.", "error");
            TriX_UI.log("Executing Python via Skulpt...", "info");
            Sk.configure({
                output: (text) => { if (text.trim()) TriX_UI.log(`[Python]: ${text.trim()}`, 'log'); },
                read: (x) => { if (Sk.builtinFiles === undefined || Sk.builtinFiles.files[x] === undefined) throw "File not found: '" + x + "'"; return Sk.builtinFiles.files[x]; }
            });
            Sk.misceval.asyncToPromise(() => Sk.importMainWithBody("<stdin>", false, code, true))
                .then(res => TriX_UI.log("Python script finished.", "info"))
                .catch(err => TriX_UI.log(err.toString(), "error"));
        },
        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) }
        })
    };
    
    const MultiTab = {
        init(gmFunctions) {
            _GM = gmFunctions;
            const TAB_ID = `tab_${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`;
            this.TAB_ID = TAB_ID;
            _GM.GM_addValueChangeListener("trix_broadcast_channel", this.listener.bind(this));
        },
        listener(name, oldValue, newValue, remote) {
            if (remote && newValue.senderId !== this.TAB_ID) {
                TriX_UI.log(`Received broadcast: ${JSON.stringify(newValue.payload)}`, "broadcast");
            }
        },
        broadcast(payload) {
            const message = { senderId: this.TAB_ID, timestamp: Date.now(), payload: payload };
            _GM.GM_setValue("trix_broadcast_channel", message);
            TriX_UI.log(`Broadcast sent: ${JSON.stringify(payload)}`, "broadcast");
        }
    };
    
    function init(username, gmFunctions) {
        TabManager.init(username, gmFunctions);
    }
    
    return { init, ScriptManager, Executor, MultiTab };
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址