KhanHack

Khan Academy Problem Solver

Устаревшая версия за 17.09.2024. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Advertisement:

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

Advertisement:

// ==UserScript==
// @name         KhanHack
// @namespace    https://greasyfork.org/users/783447
// @version      5.0
// @description  Khan Academy Problem Solver
// @author       Logzilla6 - IlyTobias
// @match        https://*.khanacademy.org/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=khanacademy.org
// ==/UserScript==
 
let mainMenu = document.createElement('div');
mainMenu.id = 'mainMenu';
mainMenu.style.position = 'fixed';
mainMenu.style.bottom = '.5vw';
mainMenu.style.left = '19vw';
mainMenu.style.width = '300px';
mainMenu.style.height = '400px';
mainMenu.style.backgroundColor = '#123576';
mainMenu.style.border = '3px solid #07152e';
mainMenu.style.borderRadius = '20px';
mainMenu.style.padding = '10px';
mainMenu.style.color = "white";
mainMenu.style.fontFamily = "Noto sans";
mainMenu.style.fontWeight = "500";
mainMenu.style.transition = "all 0.3s ease";
 
let answerBlocks = [];
let currentCombinedAnswer = '';
 
const setMainMenuContent = () => {
    mainMenu.innerHTML =`
        <div id="menuContent" style="display: flex; flex-direction: column; align-items: center; position: relative; gap: 10px; opacity: 1; transition: opacity 0.5s ease;">
            <head>
                <img id="discordIcon" src="https://i.ibb.co/grF973h/discord.png" alt="Discord" style="position: absolute; left: 7px; top: 8px; width: 24px; height: 24px; opacity: 1; transition: opacity 0.5s ease; cursor: pointer;" />
                <img id="headerImage" src="https://i.ibb.co/pX592fL/khanhack.png" style="width: 170px; opacity: 1; transition: opacity 0.5s ease;" />
                <img id="gearIcon" src="https://i.ibb.co/q0QVKGG/gearicon.png" alt="Settings" style="position: absolute; right: 7px; top: 7px; width: 24px; height: 24px; opacity: 1; transition: opacity 0.5s ease; cursor: pointer;" />
            </head>
            <div id="answerList" style="width: 100%; display: flex; flex-direction: column; gap: 10px;"></div>
        </div>
 
        <img id="toggleButton" src="https://i.ibb.co/RpqPcR1/hamburger.png" style="width: 20px; height: 20px; left: 0; right: 0;" class="toggleButton">
        <img id="clearButton" src="https://i.ibb.co/VYs1BPQ/can.png" style="width: 20px; height: 20px; bottom: 10px; right: 8px; position: absolute; cursor: pointer;" class="clearButton">
 
 
 
        <style>
            @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap');
 
            .toggleButton {
                position: absolute;
                bottom: 3px;
                left: 2px;
                background-color: #123576;
                color: white;
                border: none;
                padding: 5px 7px;
                border-radius: 15px;
                cursor: pointer;
                font-size: 15px;
                font-family: "Noto Sans";
                font-weight: 500;
            }
 
            .block {
                width: 93.5%;
                height: 40px;
                background-color: #f0f0f0;
                padding: 10px;
                border-radius: 10px;
                opacity: 1;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: opacity 0.5s ease;
            }
 
            .answer {
                margin: 0;
                text-align: center;
                color: black;
                font-family: "Noto Sans";
                font-weight: 500;
            }
 
            .imgBlock img {
                width: 250px;
                border-radius: 10px;
            }
        </style>
    `
    addToggle();
    addSettings();
    addDiscord();
    addClear();
 
    const answerList = document.getElementById('answerList');
    answerList.innerHTML = '';
 
    answerBlocks.forEach(block => {
        if (block.type === 'text') {
            addAnswerBlock(block.content, false);
        } else if (block.type === 'image') {
            addImgAnswerBlock(block.content, false);
        }
    });
};
 
const addAnswerBlock = (answer, save = true) => {
    const answerList = document.getElementById('answerList');
    const block = document.createElement('div');
    block.className = 'block';
 
    const p = document.createElement('p');
    p.className = 'answer';
    p.innerText = `Answer: ${answer}`;
 
    block.appendChild(p);
    answerList.appendChild(block);
 
    if (save) {
        answerBlocks.push({ type: 'text', content: answer });
    }
};
 
const addImgAnswerBlock = (imgSrc, save = true) => {
    const answerList = document.getElementById('answerList');
    const block = document.createElement('div');
    block.className = 'block imgBlock';
 
    const img = document.createElement('img');
    img.src = imgSrc;
 
    block.appendChild(img);
    answerList.appendChild(block);
 
    if (save) {
        answerBlocks.push({ type: 'image', content: imgSrc });
    }
};
 
let isMenuVisible = true;
const addToggle = () => {
    document.getElementById('toggleButton').addEventListener('click', function() {
        const clearButton = document.getElementById('clearButton');
        if (isMenuVisible) {
            mainMenu.style.height = '15px';
            mainMenu.style.width = '15px';
            document.getElementById('menuContent').style.opacity = '0';
            clearButton.style.opacity = '0';
            setTimeout(() => {
                document.getElementById('menuContent').style.display = 'none';
                clearButton.style.display = 'none';
            }, 50);
        } else {
            mainMenu.style.height = '400px';
            mainMenu.style.width = '300px';
            document.getElementById('menuContent').style.display = 'flex';
            clearButton.style.display = 'block';
            setTimeout(() => {
                document.getElementById('menuContent').style.opacity = '1';
                clearButton.style.opacity = '1';
            }, 100);
        }
        isMenuVisible = !isMenuVisible;
    });
};
 
 
const addSettings = () => {
    document.getElementById('gearIcon').addEventListener('click', function() {
        mainMenu.innerHTML = `
            <div id="settingsContent" style="display: flex; flex-direction: column; align-items: center; position: relative; opacity: 1; transition: opacity 0.5s ease;">
                <img id="backArrow" src="https://i.ibb.co/Jt4qrD7/pngwing-com-1.png" alt="Back" style="position: absolute; left: 7px; top: 3px; width: 24px; height: 24px; opacity: 1; transition: opacity 0.5s ease; cursor: pointer;" />
 
                <h3 style="margin: 0; text-align: center; color: white; font-family: Noto sans; font-weight: 500;">Settings Menu</h3>
                <p style="text-align: center; color: white; font-family: Noto sans; margin-top: 15px;">Ghost Mode: (Coming Soon)</p>
                <p style="text-align: center; color: white; font-family: Noto sans; margin-top: 15px;">Auto Answer: (Coming Soon)</p>
                <p style="text-align: center; color: white; font-family: Noto sans; margin-top: 15px;">Point Farmer: (Coming Soon)</p>
 
                <p style="text-align: center; color: white; font-family: Noto sans; margin-top: 180px;">KhanHack™</p>
 
                <style>
                    @import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap');
 
                </style>
            </div>
        `
        document.getElementById('backArrow').addEventListener('click', setMainMenuContent);
    });
};
 
const addDiscord = () => {
    document.getElementById('discordIcon').addEventListener('click', function() {
        window.open('https://discord.gg/khanhack', '_blank');
    });
};
 
const addClear = () => {
    document.getElementById('clearButton').addEventListener('click', function() {
        location.reload()
    });
};
 
document.body.appendChild(mainMenu);
setMainMenuContent();
 
let originalJson = JSON.parse;
JSON.parse = function (jsonString) {
    let parsedData = originalJson(jsonString);
    try {
        let itemData = JSON.parse(parsedData.data.assessmentItem.item.itemData);
 
        for (let widgetKey in itemData.question.widgets) {
            let widget = itemData.question.widgets[widgetKey];
            switch (widget.type) {
                case "numeric-input":
                    handleNumeric(widget);
                    break;
                case "radio":
                    handleRadio(widget);
                    break;
                case "expression":
                    handleExpression(widget);
                    break;
                case "dropdown":
                    handleDropdown(widget);
                    break;
                default:
                    console.log("Unknown widget: " + widget.type);
                    break;
            }
        }
        if (currentCombinedAnswer.trim() !== '') {
            addAnswerBlock(currentCombinedAnswer.trim());
            currentCombinedAnswer = '';
        }
 
    } catch (error) {
 
    }
    return parsedData;
};
 
 
function cleanLatexExpression(answer) {
    return answer
        .replace(/\\times/g, '×')
        .replace(/\\frac{([^}]*)}{([^}]*)}/g, '($1/$2)')
        .replace(/\\cdot/g, '⋅')
        .replace(/\\left|\\right/g, '')
        .replace(/[\$]/g, '')
        .replace(/\^/g, '^')
        .replace(/\\(?:[a-zA-Z]+)/g, '')
        .replace(/(?<!\\){|}/g, '');
}
 
function handleRadio(widget) {
    let content = widget.options.choices.filter(item => item.correct === true).map(item => item.content);
    let combinedAnswers = '';
    let hasImage = false;
    let imageUrl = null;
 
    content.forEach(answer => {
        const regex = answer.match(/:\/\/(.*?)\)/);
 
        if (regex) {
            const finalImg = "https" + regex[0].slice(0, -1) + ".svg";
            hasImage = true;
            imageUrl = finalImg;
        } else {
            const cleanedAnswer = cleanLatexExpression(answer);
            combinedAnswers += cleanedAnswer + ', ';
        }
    });
    combinedAnswers = combinedAnswers.trim().replace(/,$/, '');
 
    if (combinedAnswers !== '') {
        currentCombinedAnswer += `${combinedAnswers}` ;
    }
 
    if (hasImage && imageUrl) {
        addImgAnswerBlock(imageUrl);
    }
}
 
function handleNumeric(widget) {
    const numericAnswer = widget.options.answers[0].value;
    currentCombinedAnswer += `${numericAnswer}, `;
}
 
function handleExpression(widget) {
    let expressionAnswer = widget.options.answerForms[0].value;
    currentCombinedAnswer += `${expressionAnswer}` ;
}
 
function handleDropdown(widget) {
    let content = widget.options.choices.filter(item => item.correct === true).map(item => item.content);
    currentCombinedAnswer += `${content[0]},` ;
}