Add script.js
This commit is contained in:
		
							
								
								
									
										162
									
								
								script.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								script.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
// ==UserScript==
 | 
			
		||||
// @name         mathtrainer.ai auto solve
 | 
			
		||||
// @namespace    http://tampermonkey.net/
 | 
			
		||||
// @version      1
 | 
			
		||||
// @description  :p
 | 
			
		||||
// @author       elias
 | 
			
		||||
// @match        https://mathtrainer.ai/*
 | 
			
		||||
// @grant        none
 | 
			
		||||
// ==/UserScript==
 | 
			
		||||
 | 
			
		||||
// made by elias @ 15 sep. 2025
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    let lastExpression = '';
 | 
			
		||||
    let isProcessing = false;
 | 
			
		||||
    let InputEvents = {};
 | 
			
		||||
 | 
			
		||||
    function hook(element) {
 | 
			
		||||
        element.addEventListener = new Proxy(element.addEventListener, {
 | 
			
		||||
            apply(target, _this, args) {
 | 
			
		||||
                const [type, listener] = args;
 | 
			
		||||
                if (_this.tagName === 'SECTION' && _this.classList.contains('answer')) {
 | 
			
		||||
                    InputEvents[type] = listener;
 | 
			
		||||
                }
 | 
			
		||||
                return target.apply(_this, args);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    hook(HTMLElement.prototype);
 | 
			
		||||
 | 
			
		||||
    function keypress(target, key) {
 | 
			
		||||
        const event = new KeyboardEvent('keydown', {
 | 
			
		||||
            key: key,
 | 
			
		||||
            code: key.length === 1 ? `Digit${key}` : (key === 'Enter' ? 'Enter' : 'Unknown'),
 | 
			
		||||
            bubbles: true,
 | 
			
		||||
            cancelable: true
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (InputEvents.keydown) {
 | 
			
		||||
            InputEvents.keydown({
 | 
			
		||||
                target: target,
 | 
			
		||||
                key: key,
 | 
			
		||||
                type: 'keydown',
 | 
			
		||||
                preventDefault: () => {},
 | 
			
		||||
                stopPropagation: () => {}
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        target.dispatchEvent(event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function evaluateMath(expression) {
 | 
			
		||||
        if (!expression) return null;
 | 
			
		||||
        expression = expression
 | 
			
		||||
            .replace(/\\times/g, '*')
 | 
			
		||||
            .replace(/×/g, '*')
 | 
			
		||||
            .replace(/÷/g, '/')
 | 
			
		||||
            .replace(/−/g, '-')
 | 
			
		||||
            .replace(/\\div/g, '/')
 | 
			
		||||
            .replace(/\\sqrt\{(\d+)\}/g, 'Math.sqrt($1)')
 | 
			
		||||
            .replace(/\\sqrt\[(\d+)\]\{(\d+)\}/g, 'Math.pow($2, 1/$1)')
 | 
			
		||||
            .replace(/\^/g, '**')
 | 
			
		||||
            .replace(/\s+/g, '');
 | 
			
		||||
        try {
 | 
			
		||||
            const result = Function('"use strict"; return (' + expression + ')')();
 | 
			
		||||
            if (Number.isFinite(result)) {
 | 
			
		||||
                if (Math.abs(result - Math.round(result)) < 1e-10) {
 | 
			
		||||
                    return Math.round(result); // round near-integers (39.99999.. -> 40)
 | 
			
		||||
                } 
 | 
			
		||||
                return result;
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function randomDelay(min, max) {
 | 
			
		||||
        return Math.floor(Math.random() * (max - min + 1)) + min;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function inputAnswer(answerSection, result) {
 | 
			
		||||
        const resultStr = String(result);
 | 
			
		||||
 | 
			
		||||
        await new Promise(resolve => setTimeout(resolve, randomDelay(300, 500)));
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < resultStr.length; i++) {
 | 
			
		||||
            keypress(answerSection, resultStr[i]);
 | 
			
		||||
 | 
			
		||||
            if (i < resultStr.length - 1) {
 | 
			
		||||
                await new Promise(resolve => setTimeout(resolve, randomDelay(300, 500)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await new Promise(resolve => setTimeout(resolve, randomDelay(300, 500)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function processQuestion() {
 | 
			
		||||
        if (isProcessing) return;
 | 
			
		||||
        isProcessing = true;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const annotation = document.querySelector('annotation[encoding="application/x-tex"]');
 | 
			
		||||
            if (!annotation) {
 | 
			
		||||
                isProcessing = false;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const expression = annotation.textContent.trim();
 | 
			
		||||
            if (!expression || expression === lastExpression) {
 | 
			
		||||
                isProcessing = false;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            lastExpression = expression;
 | 
			
		||||
 | 
			
		||||
            const result = evaluateMath(expression);
 | 
			
		||||
            if (result === null) {
 | 
			
		||||
                isProcessing = false;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // console.log("Detected:", expression);
 | 
			
		||||
            // console.log("Answer:", result);
 | 
			
		||||
 | 
			
		||||
            const answerSection = document.querySelector('section.answer');
 | 
			
		||||
            if (!answerSection) {
 | 
			
		||||
                isProcessing = false;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await inputAnswer(answerSection, result);
 | 
			
		||||
 | 
			
		||||
            // keypress(answerSection, 'Enter');
 | 
			
		||||
            // not needed as it gets auto-entered
 | 
			
		||||
            isProcessing = false;
 | 
			
		||||
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            isProcessing = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const observer = new MutationObserver(() => {
 | 
			
		||||
        processQuestion();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    observer.observe(document.body, {
 | 
			
		||||
        childList: true,
 | 
			
		||||
        subtree: true,
 | 
			
		||||
        attributes: true
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // sometimes observer doesnt catch it :(
 | 
			
		||||
    // use interval loop as fallback
 | 
			
		||||
    setInterval(() => {
 | 
			
		||||
        if (!isProcessing) {
 | 
			
		||||
            processQuestion();
 | 
			
		||||
        }
 | 
			
		||||
    }, 500);
 | 
			
		||||
})();
 | 
			
		||||
		Reference in New Issue
	
	Block a user