Add script.js

This commit is contained in:
2025-09-17 11:56:41 +02:00
commit 07b8fd5c7a

162
script.js Normal file
View 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);
})();