TriX Python Runner Library

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

Този скрипт не може да бъде инсталиран директно. Това е библиотека за други скриптове и може да бъде използвана с мета-директива // @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;
})();