A modern, powerful developer toolkit and script executor for enhancing your web experience. Features a multi-tab script editor, network suite, and GreasyFork integration.
当前为
// ==UserScript==
// @name TriX Executor (REVAMP)
// @namespace https://greasyfork.org/en/users/COURTESYCOIL
// @version 5.0.5
// @description A modern, powerful developer toolkit and script executor for enhancing your web experience. Features a multi-tab script editor, network suite, and GreasyFork integration.
// @author Painsel
// @match https://territorial.io/*
// @match https://fxclient.github.io/FXclient/*
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_getClipboard
// @grant unsafeWindow
// @license MIT
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzRmNDZlNSI+PHBhdGggZD0iTTE4LjM2IDIyLjA1bC00LjQyLTQuNDJDMTMuNDcgMTcuODcgMTMgMTguMTcgMTMgMTguNUMxMyAyMC45OSAxNS4wMSAyMyAxNy41IDIzaDMuNTRjLTIuNDUtMS40OC00LjQyLTMuNDUtNS4LTUuOTV6TTggMTNjMS42NiAwIDMuMTgtLjU5IDQuMzgtMS42MkwxMCAxMy41VjIybDIuNS0yLjVMMTggMTMuOTZjLjM1LS40OC42NS0xIC44Ny0xLjU1QzE4LjYxIDEzLjQxIDE4IDEyLjM0IDE4IDEyVjBoLTJ2MTJjMCAuMzQtLjAyLjY3LS4wNiAxLS4zMy4xOC0uNjguMy0xLjA0LjM3LTEuNzMgMC0zLjI3LS45My00LjE2LTIuMzZMNiAxMy42VjVINXY4eiIvPjwvc3ZnPg==
// ==/UserScript==
(function () {
"use strict";
// --- TriX Core: WebSocket Logging & Global State ---
let isLoggerSuspended = false;
let customWs = null;
const monitoredConnections = new Map();
let updateConnectionStatus = () => {};
let updatePingDisplay = () => {};
let logPacketCallback = () => {};
let onConnectionStateChange = () => {};
let settings = { theme: 'dark', antiScam: true, autoUpdate: true, blockPropaganda: true };
const savedSettings = GM_getValue("settings", null);
if (savedSettings) {
settings = { ...settings, ...JSON.parse(savedSettings) };
} else {
GM_setValue("settings", JSON.stringify(settings));
}
const OriginalWebSocket = unsafeWindow.WebSocket;
unsafeWindow.WebSocket = function(url, protocols) {
let isGameSocket = false;
try {
const isTerritorial = window.location.hostname.includes('territorial.io') || document.querySelector('meta[content="FXclient"]');
const urlObj = new URL(url, window.location.href);
const urlString = urlObj.toString();
const proxyParam = urlObj.searchParams.get('u');
isGameSocket = isTerritorial && (urlString.includes('/s52/') || (proxyParam && atob(proxyParam).includes('/s52/')));
} catch (e) { /* Invalid URL */ }
if (!isGameSocket) return new OriginalWebSocket(url, protocols);
console.log(`[TriX] Intercepting WebSocket: ${url}`);
const ws = new OriginalWebSocket(url, protocols);
monitoredConnections.set(ws, { url, state: 'CONNECTING', log: [] });
onConnectionStateChange();
const originalSend = ws.send.bind(ws);
ws.send = function(data) {
if (settings.blockPropaganda && data && data.length === 2 && data[0] === 30 && data[1] === 40) {
console.log('[TriX] Blocked propaganda packet.');
return;
}
logPacketCallback(ws, 'send', data);
return originalSend(data);
};
ws.addEventListener('message', event => { logPacketCallback(ws, 'receive', event.data); });
ws.addEventListener('open', () => { const c = monitoredConnections.get(ws); if (c) c.state = 'OPEN'; onConnectionStateChange(); updateConnectionStatus('connected', 'Connection Established'); });
ws.addEventListener('close', () => { monitoredConnections.delete(ws); onConnectionStateChange(); updateConnectionStatus('disconnected', 'Disconnected'); });
ws.addEventListener('error', () => { monitoredConnections.delete(ws); onConnectionStateChange(); updateConnectionStatus('error', 'Connection Error'); });
unsafeWindow.trixSocket = ws;
return ws;
};
// --- UI & Music Player State ---
let isMinimized = false;
let currentTab = "home";
let activeNetworkTab = "logger";
let scriptTabs = [{ id: "tab1", name: "Script 1", content: "// Welcome to the revamped TriX Executor!\nconsole.log('Phoenix Rising!');" }];
let activeScriptTab = "tab1";
const musicPlayerState = { audio: new Audio(), currentAlbum: "All Songs", currentSongIndex: -1, isPlaying: false, songs: [] };
let isMusicInitialized = false;
if (!GM_getValue("scripts", null)) GM_setValue("scripts", JSON.stringify([]));
// --- CSS Styles ---
const styles = `
.trix-executor { position: fixed; top: 50px; right: 50px; width: 650px; height: 500px; background: linear-gradient(135deg, #1e1e2e 0%, #2d2d44 100%); border-radius: 12px; box-shadow: 0 20px 40px rgba(0,0,0,0.3); z-index: 999999; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: #fff; overflow: hidden; transition: all 0.3s ease; display: flex; flex-direction: column; }
.trix-header { background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%); height: 40px; display: flex; justify-content: space-between; align-items: center; padding: 0 10px 0 15px; border-radius: 12px 12px 0 0; flex-shrink: 0; cursor: move; user-select: none; }
.trix-title-area { display: flex; align-items: center; gap: 15px; }
#trix-user-profile { display: none; align-items: center; gap: 8px; }
#trix-user-pfp { width: 24px; height: 24px; border-radius: 50%; border: 2px solid rgba(255,255,255,0.5); }
#trix-user-name { font-size: 12px; font-weight: 600; }
.trix-title { font-weight: 600; font-size: 14px; color: #fff; display: flex; align-items: center; }
.revamp-badge { display: inline-block; margin-left: 8px; padding: 2px 6px; font-size: 9px; font-weight: 700; background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%); color: #422006; border-radius: 4px; vertical-align: middle; transform: translateY(-1px); }
.trix-header-info { display: flex; align-items: center; gap: 15px; font-size: 12px; color: rgba(255,255,255,0.8); }
#trix-conn-status { width: 10px; height: 10px; border-radius: 50%; background-color: #ef4444; transition: background-color 0.3s; }
#trix-conn-status.connected { background-color: #10b981; } #trix-conn-status.error { background-color: #f59e0b; }
.trix-controls { display: flex; align-items: center; gap: 8px; }
.trix-btn { width: 20px; height: 20px; border-radius: 4px; border: none; cursor: pointer; font-size: 12px; font-weight: bold; display: flex; justify-content: center; align-items: center; padding: 0; transition: all 0.2s ease; }
.minimize-btn { background: #fbbf24; color: #92400e; } .maximize-btn { background: #10b981; color: #065f46; } .close-btn { background: #ef4444; color: #991b1b; }
.trix-btn:hover { transform: scale(1.1); box-shadow: 0 2px 8px rgba(0,0,0,0.3); }
.trix-body { display: flex; height: 100%; overflow: hidden; }
.trix-sidebar { width: 150px; background: rgba(0,0,0,0.2); padding: 15px 0; border-right: 1px solid rgba(255,255,255,0.1); flex-shrink: 0; }
.sidebar-item { padding: 12px 20px; cursor: pointer; transition: all 0.2s ease; font-size: 13px; border-left: 3px solid transparent; }
.sidebar-item:hover { background: rgba(255,255,255,0.1); border-left-color: #4f46e5; }
.sidebar-item.active { background: rgba(79,70,229,0.3); border-left-color: #4f46e5; }
.trix-content { flex: 1; padding: 20px; overflow-y: auto; }
.content-section { display: none; height: 100%; box-sizing: border-box; } .content-section.active { display: block; }
.script-input, .network-textarea { width: 100%; height: 200px; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.2); border-radius: 8px; padding: 15px; color: #fff; font-family: 'Courier New', monospace; font-size: 12px; resize: vertical; outline: none; box-sizing: border-box; }
.script-tabs, .network-tabs { display: flex; gap: 5px; margin-bottom: 10px; flex-wrap: wrap; }
.script-tab, .network-tab { background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; padding: 6px 12px; font-size: 11px; cursor: pointer; transition: all 0.2s ease; position: relative; }
.script-tab.active, .network-tab.active { background: rgba(79,70,229,0.5); border-color: #4f46e5; }
.add-tab-btn { background: rgba(16,185,129,0.3); border: 1px solid #10b981; color: #10b981; border-radius: 6px; padding: 6px 12px; font-size: 11px; cursor: pointer; transition: all 0.2s ease; }
.executor-buttons { display: flex; gap: 10px; margin-top: 15px; flex-wrap: wrap; }
.exec-btn { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); border: none; border-radius: 6px; padding: 10px 20px; color: #fff; font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; }
.exec-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(79,70,229,0.4); }
.exec-btn.secondary { background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%); }
.exec-btn.success { background: linear-gradient(135deg, #10b981 0%, #059669 100%); }
.exec-btn.danger { background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); }
.search-input { width: 100%; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.2); border-radius: 8px; padding: 12px; color: #fff; font-size: 13px; margin-bottom: 15px; outline: none; box-sizing: border-box; }
.script-cards { display: grid; gap: 15px; max-height: 300px; overflow-y: auto; }
.script-card { background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.2); border-radius: 8px; padding: 15px; cursor: pointer; transition: all 0.2s ease; }
.script-card:hover { background: rgba(255,255,255,0.1); transform: translateY(-2px); }
.card-title { font-weight: 600; margin-bottom: 5px; color: #818cf8; }
.card-description { font-size: 12px; color: rgba(255,255,255,0.7); }
.settings-group { margin-bottom: 20px; }
.settings-label { display: flex; align-items: center; margin-bottom: 8px; font-weight: 600; font-size: 13px; }
.settings-checkbox { margin-right: 10px; width: 16px; height: 16px; accent-color: #4f46e5; }
.settings-input, .settings-select { width: 100%; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; padding: 10px; color: #fff; font-size: 12px; outline: none; box-sizing: border-box; }
.notification { position: fixed; top: 20px; right: 20px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); color: #fff; padding: 12px 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 1000000; font-size: 13px; font-weight: 600; opacity: 0; transform: translateX(100%); transition: all 0.3s ease; }
.notification.show { opacity: 1; transform: translateX(0); }
.minimized-icon { position: fixed; width: 50px; height: 50px; background-color: #1e1e2e; border: 3px solid #4f46e5; border-radius: 12px; cursor: pointer; z-index: 999999; transition: all 0.2s ease; box-shadow: 0 8px 25px rgba(0,0,0,0.3); display: flex; justify-content: center; align-items: center; font-size: 24px; font-weight: bold; color: #818cf8; user-select: none; }
.minimized-icon:hover { transform: scale(1.05); box-shadow: 0 12px 35px rgba(79,70,229,0.4); }
.network-view-content { margin-top: 15px; height: calc(100% - 50px); display: flex; flex-direction: column; }
.packet-log { height: 100%; overflow-y: auto; background: rgba(0,0,0,0.2); padding: 10px; border-radius: 8px; font-family: 'Courier New', monospace; font-size: 12px; }
.log-item { padding: 4px; border-bottom: 1px solid rgba(255,255,255,0.1); word-break: break-all; }
.log-item.send { color: #6ee7b7; } .log-item.receive { color: #f0abfc; }
.storage-table { display: grid; grid-template-columns: 150px 1fr auto; gap: 10px; align-items: center; font-size: 12px; padding: 8px 0; border-bottom: 1px solid rgba(255,255,255,0.1); }
.storage-key { color: #f0abfc; font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.storage-value { color: #6ee7b7; word-break: break-all; }
.trix-content::-webkit-scrollbar, .script-cards::-webkit-scrollbar, .packet-log::-webkit-scrollbar, .music-song-list::-webkit-scrollbar { width: 8px; }
.trix-content::-webkit-scrollbar-track, .script-cards::-webkit-scrollbar-track, .packet-log::-webkit-scrollbar-track, .music-song-list::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); border-radius: 4px; }
.trix-content::-webkit-scrollbar-thumb, .script-cards::-webkit-scrollbar-thumb, .packet-log::-webkit-scrollbar-thumb, .music-song-list::-webkit-scrollbar-thumb { background: rgba(79,70,229,0.6); border-radius: 4px; }
/* --- Music Player Styles --- */
.trixmusic-container { display: grid; grid-template-columns: 1fr 1.5fr; gap: 20px; height: 100%; }
.music-playlist-panel, .music-player-panel { display: flex; flex-direction: column; background: rgba(0,0,0,0.2); border-radius: 8px; padding: 15px; }
.music-player-panel { justify-content: center; align-items: center; }
.music-playlist-header { display: grid; grid-template-columns: 1fr; gap: 10px; margin-bottom: 10px; }
.music-song-list { overflow-y: auto; flex-grow: 1; }
.music-song-item { padding: 10px; cursor: pointer; border-radius: 6px; transition: background-color 0.2s; }
.music-song-item:hover, .music-song-item.playing { background-color: #2d2d44; }
.music-song-title { display: block; font-weight: 600; color: #fff; }
.music-song-artist { font-size: 12px; color: #a5b4fc; }
.music-info { text-align: center; margin-bottom: 20px; }
.music-title { font-size: 22px; font-weight: 700; display: block; color: #fff; }
.music-artist { font-size: 14px; color: #a5b4fc; }
.music-progress-container { width: 80%; background: rgba(0,0,0,0.3); border-radius: 5px; cursor: pointer; height: 8px; margin: 15px 0; }
.music-progress-bar { background: #4f46e5; width: 0%; height: 100%; border-radius: 5px; }
.music-controls { display: flex; justify-content: center; align-items: center; gap: 20px; margin: 15px 0; }
.music-control-btn { background: none; border: none; color: #c7d2fe; cursor: pointer; font-size: 24px; opacity: 0.8; transition: all 0.2s; }
.music-control-btn:hover { opacity: 1; color: #fff; transform: scale(1.1); }
#music-play-pause-btn { font-size: 36px; }
#music-volume-slider { width: 50%; accent-color: #4f46e5; }
`;
const styleSheet = document.createElement("style");
styleSheet.textContent = styles;
document.head.appendChild(styleSheet);
function createExecutorPanel() {
const panel = document.createElement("div");
panel.className = "trix-executor";
panel.innerHTML = `
<div class="trix-header">
<div class="trix-title-area">
<div id="trix-user-profile">
<img id="trix-user-pfp" src="">
<span id="trix-user-name"></span>
</div>
<div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div>
<div class="trix-title">TriX Executor v5.0.2 <span class="revamp-badge">REVAMP</span></div>
</div>
<div class="trix-header-info">
<div id="trix-conn-status" title="Disconnected"></div>
<span id="trix-ping-display">Ping: ---</span>
<span id="trix-fps-display">FPS: --</span>
</div>
<div class="trix-controls">
<button class="trix-btn minimize-btn" title="Minimize">−</button>
<button class="trix-btn maximize-btn" title="Maximize">□</button>
<button class="trix-btn close-btn" title="Close">×</button>
</div>
</div>
<div class="trix-body">
<div class="trix-sidebar">
<div class="sidebar-item active" data-tab="home">🏠 Home</div>
<div class="sidebar-item" data-tab="main">⚡ Main</div>
<div class="sidebar-item" data-tab="network">📡 Network</div>
<div class="sidebar-item" data-tab="cloud">☁ Cloud</div>
<div class="sidebar-item" data-tab="files">📁 Files</div>
<div class="sidebar-item" data-tab="trixmusic">🎵 TrixMusic</div>
<div class="sidebar-item" data-tab="settings">⚙ Settings</div>
</div>
<div class="trix-content">
${createHomeContent()}
${createMainContent()}
${createNetworkContent()}
${createCloudContent()}
${createFilesContent()}
${createTrixMusicContent()}
${createSettingsContent()}
</div>
</div>
`;
document.body.appendChild(panel);
return panel;
}
// --- MINIFIED HELPER FUNCTIONS ---
function showNotification(message, type = "success") { const n = document.createElement("div"); n.className="notification"; n.textContent=message; if(type==="error"){n.style.background="linear-gradient(135deg, #ef4444 0%, #dc2626 100%)";} document.body.appendChild(n); setTimeout(()=>n.classList.add("show"),100); setTimeout(()=>{n.classList.remove("show"); setTimeout(()=>n.remove(),300)},3000); }
function createHomeContent() { return `<div class="content-section active" id="home-content"><h2>Script Store</h2><input type="text" class="search-input" placeholder="Search saved scripts..." id="script-search"><div class="script-cards" id="saved-scripts"></div></div>`; }
function createMainContent() { return `<div class="content-section" id="main-content"><h2>Live JS Executor</h2><div class="script-tabs" id="script-tabs"></div><textarea class="script-input" placeholder="Enter Script Here..." id="script-editor"></textarea><div class="executor-buttons"><button class="exec-btn" id="execute-btn">Execute</button><button class="exec-btn secondary" id="execute-clipboard-btn">Execute Clipboard</button><button class="exec-btn success" id="save-script-btn">Save Script</button></div></div>`; }
function createCloudContent() { return `<div class="content-section" id="cloud-content"><h2>GreasyFork Scripts</h2><input type="text" class="search-input" placeholder="Search GreasyFork..." id="greasyfork-search"><div class="script-cards" id="cloud-results"></div></div>`; }
function createFilesContent() { return `<div class="content-section" id="files-content"><h2>File Explorer</h2><p style="font-size:12px; color: #ccc; margin-bottom:10px;">A read-only view of data this script has stored in your browser.</p><div class="script-cards" id="file-explorer-view"></div></div>`; }
function createNetworkContent() { return `<div class="content-section" id="network-content"><div class="network-tabs"><div class="network-tab active" data-net-tab="logger">Logger</div><div class="network-tab" data-net-tab="injector">Injector</div><div class="network-tab" data-net-tab="ws_client">WS Client</div><div class="network-tab" data-net-tab="storage">Storage</div></div><div class="network-view-content"></div></div>`; }
function createTrixMusicContent() { return `<div class="content-section trixmusic-container" id="trixmusic-content"><div class="music-playlist-panel"><div class="music-playlist-header"><select class="settings-select" id="music-album-select"></select></div><input type="text" class="search-input" id="music-search-input" placeholder="Search songs..." style="margin-bottom: 10px;"><div class="music-song-list"></div></div><div class="music-player-panel"><div class="music-info"><span class="music-title">Select a Song</span><span class="music-artist">TrixMusic</span></div><div class="music-progress-container"><div class="music-progress-bar"></div></div><div class="music-controls"><button class="music-control-btn" id="music-prev-btn">⏮️</button><button class="music-control-btn" id="music-play-pause-btn">▶️</button><button class="music-control-btn" id="music-next-btn">⏭️</button></div><input type="range" id="music-volume-slider" min="0" max="1" step="0.01" value="0.5" title="Volume"></div></div>`; }
function createSettingsContent() { const s = settings; return `<div class="content-section" id="settings-content"><h2>Settings</h2><div class="settings-group"><label class="settings-label"><input type="checkbox" class="settings-checkbox" id="block-propaganda" ${s.blockPropaganda ? "checked" : ""}>Block Propaganda Popups (for territorial.io)</label></div><div class="settings-group"><label class="settings-label"><input type="checkbox" class="settings-checkbox" id="anti-scam" ${s.antiScam ? "checked" : ""}>Anti-Scam Protection (confirm potentially harmful scripts)</label></div><div class="settings-group"><label class="settings-label"><input type="checkbox" class="settings-checkbox" id="auto-update" ${s.autoUpdate ? "checked" : ""} disabled>Auto Update Scripts (Future Feature)</label></div></div>`; }
function renderActiveNetworkView() { const c=document.querySelector("#network-content .network-view-content"); if(!c)return; c.innerHTML=""; switch(activeNetworkTab){case "logger": c.innerHTML=`<div class="executor-buttons" style="margin-top:0; margin-bottom:10px;"><button class="exec-btn" id="suspend-log-btn">Suspend Log</button><button class="exec-btn secondary" id="clear-log-btn">Clear Log</button></div><div class="packet-log" id="packet-log-output">Waiting for connection...</div>`; renderPacketLog(); break; case "injector": c.innerHTML=`<h3>Packet Injector</h3><p style="font-size:12px; color: #ccc; margin-bottom:10px;">Send a custom packet to the current game connection.</p><textarea class="network-textarea" id="injector-input" placeholder='e.g., 42["chat","Hello from TriX!"]' style="height: 150px;"></textarea><div class="executor-buttons"><button class="exec-btn" id="inject-packet-btn">Inject Packet</button></div>`; break; case "ws_client": c.innerHTML=`<h3>WebSocket Client</h3><input type="text" id="ws-client-url" class="search-input" placeholder="wss://your-socket-url.com"><div class="executor-buttons" style="margin-top:0;"><button class="exec-btn" id="ws-client-connect-btn">Connect</button></div><div class="packet-log" id="ws-client-log" style="height: 150px; margin-top:10px;"></div><textarea class="network-textarea" id="ws-client-input" placeholder="Message to send..." style="height: 80px; margin-top:10px;"></textarea><div class="executor-buttons"><button class="exec-btn" id="ws-client-send-btn">Send</button></div>`; break; case "storage": c.innerHTML=`<h3>Storage Explorer</h3><h4>Local Storage</h4><div id="local-storage-view"></div><h4 style="margin-top:20px;">Session Storage</h4><div id="session-storage-view"></div>`; renderStorageView(); break; } }
function renderPacketLog() { const l=document.getElementById("packet-log-output"); if(!l)return; const a=Array.from(monitoredConnections.values()).find(c=>c.state==='OPEN'||c.log.length>0); if(!a){l.textContent='Waiting for active connection...'; return;} if(isLoggerSuspended)return; l.innerHTML=''; a.log.forEach(p=>{const i=document.createElement('div'); i.className=`log-item ${p.type}`; i.textContent=`[${p.type.toUpperCase()}] ${p.data}`; l.appendChild(i);}); l.scrollTop=l.scrollHeight; }
function renderStorageView() { const l=document.getElementById('local-storage-view'),s=document.getElementById('session-storage-view'); if(!l||!s)return; const c=(st,t)=>{let h=''; for(let i=0;i<st.length;i++){const k=st.key(i),v=st.getItem(k); h+=`<div class="storage-table"><div class="storage-key" title="${k}">${k}</div><div class="storage-value" title="${v}">${v}</div><button class="exec-btn danger storage-delete-btn" data-type="${t}" data-key="${k}" style="padding: 5px 8px; font-size:10px;">X</button></div>`;} return h||'<div style="font-size:12px; color:#888; padding: 10px 0;">Empty</div>';}; l.innerHTML=c(localStorage,'local'); s.innerHTML=c(sessionStorage,'session'); }
function loadFileExplorer() { const c=document.getElementById("file-explorer-view"); if(!c)return; c.innerHTML=""; const s=JSON.parse(GM_getValue("scripts","[]")), t=JSON.parse(GM_getValue("settings","{}")); const f=[{name:"scripts.json",type:"GM Storage",size:`${JSON.stringify(s).length} bytes`},{name:"settings.json",type:"GM Storage",size:`${JSON.stringify(t).length} bytes`},...s.map(s=>({name:s.name,type:'Saved Script',size:`${s.code.length} chars`}))]; f.forEach(file=>{const a=document.createElement("div"); a.className="script-card"; a.style.cursor="default"; a.innerHTML=`<div class="card-title">📄 ${file.name}</div><div class="card-description">${file.type} • ${file.size}</div>`; c.appendChild(a);}); }
function createMinimizedIcon() { const i=document.createElement("div"); i.className="minimized-icon"; i.title="TriX Executor"; i.style.top="50px"; i.style.right="50px"; i.textContent="T"; document.body.appendChild(i); let d=!1,o={x:0,y:0}; i.addEventListener("mousedown",e=>{d=!0;const r=i.getBoundingClientRect();o={x:e.clientX-r.left,y:e.clientY-r.top};e.preventDefault();}); document.addEventListener("mousemove",e=>{if(d){const x=e.clientX-o.x,y=e.clientY-o.y; i.style.left=Math.max(0,Math.min(x,window.innerWidth-i.offsetWidth))+"px"; i.style.top=Math.max(0,Math.min(y,window.innerHeight-i.offsetHeight))+"px"; i.style.right="auto";}}); document.addEventListener("mouseup",e=>{if(d){d=!1;if(e.target===i)restorePanel();}}); return i; }
function minimizePanel() { const p=document.querySelector(".trix-executor"); if(p){p.style.display="none"; isMinimized=!0; createMinimizedIcon();} }
function restorePanel() { const p=document.querySelector(".trix-executor"), i=document.querySelector(".minimized-icon"); if(p)p.style.display="flex"; if(i)i.remove(); isMinimized=!1; }
function closePanel() { const p=document.querySelector(".trix-executor"); if(p)p.remove(); }
function switchTab(tabName) { document.querySelectorAll(".sidebar-item").forEach(i=>i.classList.remove("active")); document.querySelector(`[data-tab="${tabName}"]`).classList.add("active"); document.querySelectorAll(".content-section").forEach(s=>s.classList.remove("active")); document.getElementById(`${tabName}-content`).classList.add("active"); currentTab=tabName; if(tabName==="home")loadSavedScripts(); else if(tabName==="main")updateScriptTabs(); else if(tabName==="network")renderActiveNetworkView(); else if(tabName==="files")loadFileExplorer(); else if(tabName==="trixmusic" && !isMusicInitialized) { initTrixMusic(); isMusicInitialized=true; } }
function updateScriptTabs() { const t=document.getElementById("script-tabs"); t.innerHTML=""; scriptTabs.forEach(tab=>{const e=document.createElement("div"); e.className=`script-tab ${tab.id===activeScriptTab?"active":""}`; e.textContent=tab.name; e.onclick=()=>switchScriptTab(tab.id); e.ondblclick=()=>renameScriptTab(tab.id); t.appendChild(e);}); const a=document.createElement("div"); a.className="add-tab-btn"; a.textContent="+"; a.onclick=addScriptTab; t.appendChild(a); const c=scriptTabs.find(tab=>tab.id===activeScriptTab); if(c)document.getElementById("script-editor").value=c.content; }
function switchScriptTab(tabId) { const c=scriptTabs.find(tab=>tab.id===activeScriptTab); if(c)c.content=document.getElementById("script-editor").value; activeScriptTab=tabId; updateScriptTabs(); }
function addScriptTab() { const n="tab"+Date.now(), t={id:n,name:`Script ${scriptTabs.length+1}`,content:""}; scriptTabs.push(t); activeScriptTab=n; updateScriptTabs(); showNotification("New tab created"); }
function renameScriptTab(tabId) { const t=scriptTabs.find(t=>t.id===tabId); if(t){const n=prompt("Enter new tab name:",t.name); if(n&&n.trim()){t.name=n.trim(); updateScriptTabs(); showNotification("Tab renamed");}}}
function executeScript(code) { try{if(settings.antiScam&&[/document\.cookie/i,/localStorage\./i,/sessionStorage\./i,/\.send\(/i,/fetch\(/i,/XMLHttpRequest/i].some(p=>p.test(code))&&!confirm("This script contains potentially suspicious code that could access your data. Are you sure you want to execute it?")){showNotification("Execution cancelled by user.","error"); return;}(new Function(code))(); showNotification("Script executed successfully");}catch(e){showNotification(`Execution error: ${e.message}`,"error"); console.error("[TriX] Script execution error:",e);}}
function saveScript() { const c=document.getElementById("script-editor").value; if(!c.trim()){showNotification("No script to save","error"); return;} const n=prompt("Enter script name:"); if(!n||!n.trim())return; const s=JSON.parse(GM_getValue("scripts")), a={id:Date.now().toString(),name:n.trim(),code:c,created:new Date().toISOString()}; s.push(a); GM_setValue("scripts",JSON.stringify(s)); showNotification("Script saved successfully"); if(currentTab==="home")loadSavedScripts(); }
function loadSavedScripts() { const s=JSON.parse(GM_getValue("scripts")), c=document.getElementById("saved-scripts"); c.innerHTML=""; s.forEach(script=>{const a=document.createElement("div"); a.className="script-card"; a.innerHTML=`<div class="card-title">${script.name}</div><div class="card-description">Created: ${new Date(script.created).toLocaleDateString()}</div><button class="exec-btn danger delete-btn" style="margin-top: 10px; padding: 5px 10px; font-size: 11px;">Delete</button>`; a.addEventListener("click",e=>{if(e.target.classList.contains("delete-btn"))return; switchTab("main"); const n={id:`loaded-${script.id}`,name:script.name,content:script.code}, t=scriptTabs.find(t=>t.id===n.id); if(!t)scriptTabs.push(n); activeScriptTab=n.id; updateScriptTabs(); showNotification(`Script "${script.name}" loaded`);}); a.querySelector(".delete-btn").addEventListener("click",e=>{e.stopPropagation(); if(confirm(`Are you sure you want to delete "${script.name}"?`)){const t=s.filter(s=>s.id!==script.id); GM_setValue("scripts",JSON.stringify(t)); showNotification("Script deleted"); loadSavedScripts();}}); c.appendChild(a);}); if(s.length===0)c.innerHTML='<div style="text-align: center; color: rgba(255,255,255,0.5); padding: 40px;">No saved scripts</div>'; }
async function searchGreasyFork(query) { if(!query.trim())return; const r=document.getElementById("cloud-results"); r.innerHTML='<div style="text-align:center; padding:20px;">Searching...</div>'; try{const e=await fetch(`https://greasyfork.org/en/scripts.json?q=${encodeURIComponent(query)}`),s=await e.json(); r.innerHTML=""; if(!s.length){r.innerHTML='<div style="text-align:center; padding:20px; color: rgba(255,255,255,0.5);">No scripts found</div>'; return;} s.slice(0,50).forEach(script=>{const c=document.createElement("div"); c.className="script-card"; c.innerHTML=`<div class="card-title">${script.name}</div><div class="card-description">${script.description||'No description.'}</div><div style="font-size:11px; color: rgba(255,255,255,0.6); margin-top:8px;">By ${script.users[0].name} • ${script.total_installs} installs</div><button class="exec-btn success" data-url="${script.code_url}" data-name="${script.name}" style="margin-top:10px; padding: 5px 10px; font-size:11px;">Load Script</button>`; c.querySelector("button").onclick=async e=>{showNotification("Loading script..."); try { const t=await fetch(e.target.dataset.url), a=await t.text(); switchTab("main"); addScriptTab(); const d=scriptTabs.find(t=>t.id===activeScriptTab); d.name=e.target.dataset.name; d.content=a; updateScriptTabs(); showNotification("Script loaded into new tab!"); } catch (err) { showNotification("Failed to load script code.", "error"); } }; r.appendChild(c);});}catch(e){r.innerHTML='<div style="text-align:center; padding:20px; color:red;">Failed to fetch scripts</div>';}}
unsafeWindow.onSignIn = function(googleUser) { const p=googleUser.getBasicProfile(),u=p.getName(),i=p.getImageUrl(),d=document.querySelector('.trix-executor #trix-user-profile'),b=document.querySelector('.trix-executor .g-signin2'),t=document.querySelector('.trix-executor .trix-title');if(d&&b){document.getElementById('trix-user-pfp').src=i;document.getElementById('trix-user-name').textContent=u;d.style.display='flex';b.style.display='none';if(t)t.style.display='none';}};
function showLoadingScreen(callback) { const ls=document.createElement('div');ls.id='trix-loading-screen';const lm=["Enhancing experience, not breaking rules.","A dev tool for curious minds.","Building, not battling.","Scripts are your superpower."];ls.innerHTML=`<div class="loading-content"><div class="loading-header">TriX Executor</div><div class="loading-bar-container"><div class="loading-bar-progress"></div></div><div class="loading-message">${lm[0]}</div></div>`;const sm=document.createElement('div');sm.id='trix-loading-settings-modal';sm.style.visibility='hidden';sm.innerHTML=`<div class="loading-content"><div class="loading-header">Settings</div><div class="settings-group" style="text-align:left; max-width: 300px; margin: 2rem auto;"><label class="settings-label">Theme</label><select class="settings-select" id="trix-theme-select-loading"><option value="dark">Dark (Default)</option></select></div><button id="trix-resume-loading" class="exec-btn" style="margin-top: 2rem;">Resume</button></div>`;const s=document.createElement('style');s.textContent=`#trix-loading-screen, #trix-loading-settings-modal { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: #11111b; z-index: 2147483647; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #fff; font-family: 'Segoe UI', sans-serif; opacity: 0; transition: opacity 0.5s ease-in-out; pointer-events: none; } #trix-loading-screen.visible, #trix-loading-settings-modal.visible { opacity: 1; pointer-events: auto; } .loading-content { opacity: 1; transition: opacity 1s ease-in-out; text-align: center; } .loading-content.fade-out { opacity: 0; } .loading-header { font-size: 5rem; font-weight: bold; color: #4f46e5; text-shadow: 2px 2px 0px #4338ca, 4px 4px 0px #312e81, 6px 6px 10px rgba(0,0,0,0.5); margin-bottom: 2rem; } .loading-bar-container { width: 50%; max-width: 600px; height: 20px; background-color: #2d2d44; border-radius: 10px; border: 1px solid #4f46e5; overflow: hidden; margin-bottom: 1rem; } .loading-bar-progress { width: 0%; height: 100%; background: linear-gradient(90deg, #7c3aed, #4f46e5); border-radius: 10px; transition: width 0.1s linear; } .loading-message { font-style: italic; color: #9ca3af; min-height: 1.2em; margin-top: 1rem; }`;document.head.appendChild(s);document.body.append(ls,sm);setTimeout(()=>ls.classList.add("visible"),10);const p=ls.querySelector('.loading-bar-progress'),m=ls.querySelector('.loading-message');let r=0;const i=setInterval(()=>{r+=Math.random()*5;p.style.width=`${Math.min(r,100)}%`;if(r>25&&r<30)m.textContent=lm[1];if(r>55&&r<60)m.textContent=lm[2];if(r>85&&r<90)m.textContent=lm[3];if(r>=100){clearInterval(i);window.removeEventListener('keydown',f);ls.querySelector('.loading-content').classList.add('fade-out');setTimeout(()=>{ls.classList.remove('visible');setTimeout(()=>{ls.remove();sm.remove();s.remove();callback();},500);},500);}},100);const f=e=>{if(e.key==='F12'){e.preventDefault();clearInterval(i);sm.style.visibility='visible';sm.classList.add('visible');}};window.addEventListener('keydown',f);sm.querySelector('#trix-resume-loading').onclick=()=>{sm.classList.remove('visible');showLoadingScreen(callback);};}
const albums = { "Phonk Mix": [{title:"Passo Bem Solto",artist:"ATLXS",url:"https://evzxirgylircpnblikrw.supabase.co/storage/v1/object/public/MOOZIK/ATLXS_-_PASSO_BEM_SOLTO_-_Slowed_@BaseNaija%20(2).mp3"}], "Rock Anthems": [{title:"Animal I Have Become",artist:"Three Days Grace",url:"https://www.dropbox.com/scl/fi/b3lgo2fkz85h0m3nklx3b/Skilet_-_Animal_I_Have_Become_-mp3.pm-1.mp3?rlkey=yok2i5r5in404ili6ozf776px&st=5xmvo7c5&dl=1"},{title:"It Has To Be This Way",artist:"Jamie Christopherson",url:"https://evzxirgylircpnblikrw.supabase.co/storage/v1/object/public/MOOZIK/Metal%20Gear%20Rising-%20Revengeance%20OST%20-%20It%20Has%20To%20Be%20This%20Way%20_Senator%20Battle_%20-%20Jamie%20Christopherson%20-%20SoundLoadMate.com.mp3"}], "Misc": [{title:"Honeypie",artist:"JAWNY",url:"https://evzxirgylircpnblikrw.supabase.co/storage/v1/object/public/MOOZIK/JAWNY_-_Honeypie_muzonov.net_(mp3.pm).mp3"}] };
const renderSongList = (filter = "") => { const { currentAlbum } = musicPlayerState; musicPlayerState.songs = (currentAlbum === "All Songs") ? Object.values(albums).flat() : albums[currentAlbum]; const listEl = document.getElementById("music-song-list"); if (!listEl) return; listEl.innerHTML = ""; musicPlayerState.songs.filter(s => s.title.toLowerCase().includes(filter) || s.artist.toLowerCase().includes(filter)).forEach((song) => { const originalIndex = Object.values(albums).flat().findIndex(s => s.url === song.url); const item = document.createElement("div"); item.className = "music-song-item" + (originalIndex === musicPlayerState.currentSongIndex ? " playing" : ""); item.innerHTML = `<span class="music-song-title">${song.title}</span><span class="music-song-artist">${song.artist}</span>`; item.onclick = () => { loadSong(originalIndex); playSong(); }; listEl.appendChild(item); }); };
const loadSong = (index) => { const allSongs = Object.values(albums).flat(); musicPlayerState.currentSongIndex = index; const song = allSongs[index]; musicPlayerState.audio.src = song.url; document.getElementById("music-title").textContent = song.title; document.getElementById("music-artist").textContent = song.artist; renderSongList(document.getElementById("music-search-input").value); };
const playSong = () => { musicPlayerState.audio.play(); musicPlayerState.isPlaying = true; document.getElementById("music-play-pause-btn").textContent = "⏸️"; };
const pauseSong = () => { musicPlayerState.audio.pause(); musicPlayerState.isPlaying = false; document.getElementById("music-play-pause-btn").textContent = "▶️"; };
const nextSong = () => { let i = musicPlayerState.currentSongIndex + 1; if (i >= Object.values(albums).flat().length) i = 0; loadSong(i); playSong(); };
const prevSong = () => { let i = musicPlayerState.currentSongIndex - 1; if (i < 0) i = Object.values(albums).flat().length - 1; loadSong(i); playSong(); };
function initTrixMusic() { const p = musicPlayerState; p.audio.ontimeupdate = () => { const progress = (p.audio.currentTime / p.audio.duration) * 100; const pb = document.getElementById("music-progress-bar"); if(pb) pb.style.width = `${progress || 0}%`; }; p.audio.onended = nextSong; const pc = document.querySelector(".music-progress-container"); if(pc) pc.onclick = e => { if(p.audio.duration) p.audio.currentTime = (e.offsetX / e.target.clientWidth) * p.audio.duration; }; const as = document.getElementById("music-album-select"); if(as) as.innerHTML = "<option>All Songs</option>" + Object.keys(albums).map(a => `<option>${a}</option>`).join(''); renderSongList(); }
// --- Initialization ---
function init() {
const panel = createExecutorPanel();
const googleApiScript = document.createElement('script'); googleApiScript.src = "https://apis.google.com/js/platform.js"; googleApiScript.async = true; googleApiScript.defer = true; document.head.appendChild(googleApiScript);
panel.addEventListener('click', async e => { if (e.target.matches('.minimize-btn')) minimizePanel(); if (e.target.matches('.maximize-btn')) { if (panel.style.width === "100vw") { Object.assign(panel.style, { width: "650px", height: "500px", top: "50px", left: "auto", right: "50px" }); } else { Object.assign(panel.style, { width: "100vw", height: "100vh", top: "0", left: "0", right: "auto" }); } } if (e.target.matches('.close-btn')) closePanel(); if (e.target.matches('#execute-btn')) executeScript(document.getElementById("script-editor").value); if (e.target.matches('#execute-clipboard-btn')) { try { const t = await GM_getClipboard(); if (t && t.trim()) executeScript(t); else showNotification("Clipboard is empty", "error"); } catch (err) { showNotification("Failed to read clipboard", "error"); } } if (e.target.matches('#save-script-btn')) saveScript(); if (e.target.matches('#suspend-log-btn')) { isLoggerSuspended = !isLoggerSuspended; e.target.textContent = isLoggerSuspended ? "Resume Log" : "Suspend Log"; e.target.classList.toggle('secondary', isLoggerSuspended); } if (e.target.matches('#clear-log-btn')) { const a = Array.from(monitoredConnections.values()).find(c => c.state === 'OPEN'); if(a) a.log = []; renderPacketLog(); } if (e.target.matches('#inject-packet-btn')) { if(unsafeWindow.trixSocket && unsafeWindow.trixSocket.readyState === 1) { unsafeWindow.trixSocket.send(document.getElementById("injector-input").value); showNotification("Packet injected"); } else { showNotification("Not connected to game server.", "error"); } } if (e.target.matches('.storage-delete-btn')) { const { type, key } = e.target.dataset; const s = type === 'local' ? localStorage : sessionStorage; if (confirm(`Delete "${key}" from ${type} storage?`)) { s.removeItem(key); renderStorageView(); } } if (e.target.matches('.sidebar-item')) switchTab(e.target.dataset.tab); if (e.target.matches('.network-tab')) { panel.querySelectorAll('.network-tab').forEach(t => t.classList.remove('active')); e.target.classList.add('active'); activeNetworkTab = e.target.dataset.netTab; renderActiveNetworkView(); } if (e.target.matches('#music-play-pause-btn')) { musicPlayerState.isPlaying ? pauseSong() : playSong(); } if (e.target.matches('#music-next-btn')) nextSong(); if (e.target.matches('#music-prev-btn')) prevSong(); });
panel.addEventListener('input', e => { if (e.target.matches('#script-editor')) { const t = scriptTabs.find(tab => tab.id === activeScriptTab); if (t) t.content = e.target.value; } if (e.target.matches('#script-search')) { const q = e.target.value.toLowerCase(); panel.querySelectorAll("#saved-scripts .script-card").forEach(c => { const t = c.querySelector(".card-title").textContent.toLowerCase(); c.style.display = t.includes(q) ? "block" : "none"; }); } if (e.target.matches('#music-search-input')) { renderSongList(e.target.value.toLowerCase()); } if (e.target.matches('#music-volume-slider')) { musicPlayerState.audio.volume = e.target.value; } });
panel.addEventListener('change', e => { if (e.target.matches('#settings-content input')) { settings.antiScam = document.getElementById("anti-scam").checked; settings.blockPropaganda = document.getElementById("block-propaganda").checked; GM_setValue("settings", JSON.stringify(settings)); showNotification("Settings saved"); } if (e.target.matches('#music-album-select')) { musicPlayerState.currentAlbum = e.target.value; renderSongList(document.getElementById('music-search-input').value); } });
panel.addEventListener('keypress', e => { if (e.target.matches('#greasyfork-search') && e.key === 'Enter') { searchGreasyFork(e.target.value); } });
let isDragging = false, dragOffset = { x: 0, y: 0 };
panel.querySelector(".trix-header").onmousedown = (e) => { if (e.target.closest(".trix-btn, .g-signin2")) return; isDragging = true; const r = panel.getBoundingClientRect(); dragOffset = { x: e.clientX - r.left, y: e.clientY - r.top }; e.preventDefault(); };
document.onmousemove = (e) => { if (isDragging && !isMinimized) { const x = e.clientX - dragOffset.x, y = e.clientY - dragOffset.y; panel.style.left = Math.max(0, Math.min(x, window.innerWidth - panel.offsetWidth)) + "px"; panel.style.top = Math.max(0, Math.min(y, window.innerHeight - panel.offsetHeight)) + "px"; panel.style.right = "auto"; } };
document.onmouseup = () => { isDragging = false; };
document.onkeydown = (e) => { if (e.ctrlKey && e.shiftKey && e.key.toUpperCase() === "E") { e.preventDefault(); const p = document.querySelector('.trix-executor'); if (!p) init(); else if (isMinimized) restorePanel(); else minimizePanel(); } };
logPacketCallback = (ws, type, data) => { const c = monitoredConnections.get(ws); if (c) { c.log.push({ type, data }); if (c.log.length > 200) c.log.shift(); if (currentTab === 'network' && activeNetworkTab === 'logger' && !isLoggerSuspended) renderPacketLog(); } };
onConnectionStateChange = () => { if(currentTab === 'network' && activeNetworkTab === 'logger') renderPacketLog(); };
updateConnectionStatus = (status, title) => { const e = document.getElementById('trix-conn-status'); if(e) { e.className = status; e.title = title; } };
updatePingDisplay = async () => { const e = document.getElementById('trix-ping-display'); if (!e) return; const s = performance.now(); try { await fetch(`${window.location.protocol}//${window.location.host}/favicon.ico?_=${Date.now()}`, { method: 'HEAD', cache: 'no-store' }); e.textContent = `Ping: ${Math.round(performance.now() - s)}`; } catch { e.textContent = 'Ping: ---'; } };
setInterval(updatePingDisplay, 5000);
let lastFrameTime = performance.now(), frameCount = 0; const fpsDisplay = document.getElementById('trix-fps-display');
function updateFPS(now) { frameCount++; if (now >= lastFrameTime + 1000) { if(fpsDisplay) fpsDisplay.textContent = `FPS: ${frameCount}`; lastFrameTime = now; frameCount = 0; } requestAnimationFrame(updateFPS); }
if (fpsDisplay) requestAnimationFrame(updateFPS);
loadSavedScripts();
updateScriptTabs();
showNotification("TriX Executor loaded! Press Ctrl+Shift+E to toggle.");
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => showLoadingScreen(init));
} else {
showLoadingScreen(init);
}
})();