TriX Python Runner Library

A dedicated library for loading the Pyodide runtime and executing Python code for TriX.

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/542306/1622816/TriX%20Python%20Runner%20Library.js

// ==UserScript==
// @name        TriX Python Runner Library
// @namespace   https://github.com/YourUsername/TriX-Executor
// @version     1.0.0
// @description A dedicated library for loading the Pyodide runtime and executing Python code for TriX.
// @author      You
// @require     https://cdn.jsdelivr.net/pyodide/v0.25.1/full/pyodide.js
// @license     MIT
// ==/UserScript==

const TriX_Python = (function() {
    'use strict';

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

        // This init function is now much simpler.
        // The @require directive ensures 'loadPyodide' is already available.
        async init(isPreloading = false, progressCallback = null) {
            if (this.pyodide || this.isLoading || this.isSkipped) return;
            this.isLoading = true;

            // Give initial feedback
            if (!isPreloading) {
                TriX_UI.setPythonStatus('loading');
                TriX_UI.log('Initializing Python runtime (Pyodide)...', 'info');
                TriX_UI.createProgressBar();
            }

            try {
                if (typeof loadPyodide !== 'function') {
                    throw new Error("Fatal: `loadPyodide` was not loaded by @require.");
                }
                
                // Use the globally available loadPyodide function
                this.pyodide = await loadPyodide({
                    indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.25.1/full/',
                    // Use the progress callback to update the loader UI
                    fullErrHandler: (err) => { if (progressCallback) progressCallback({ what: err }) },
                    stdout: (msg) => { if (progressCallback) progressCallback({ what: msg }) },
                });
                
                // Final success feedback
                if (!isPreloading) {
                    document.getElementById('trix-py-progress-container')?.remove();
                    TriX_UI.log('Python runtime ready.', 'info');
                    TriX_UI.setPythonStatus('ready');
                }
            } catch (err) {
                if (!isPreloading) {
                    document.getElementById('trix-py-progress-container')?.remove();
                    TriX_UI.setPythonStatus('error');
                }
                TriX_UI.log(`Error loading Pyodide: ${err.message}.`, 'error');
                throw err;
            } finally {
                this.isLoading = false;
            }
        },

        async run(code, packages) {
            if (this.isSkipped) return TriX_UI.log('Python was skipped during startup. Please reload to enable.', 'warn');
            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);
                    if (packageList.length > 0) {
                        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');
            }
        }
    };

    return PyodideManager;
})();