Greasy Fork is available in English.

KhanHack 6.0

Khan Academy Answer Hack

< Feedback on KhanHack 6.0

Question/comment

§
Posted: 18.12.2024.

its me here uhmm i am working to fix the userscript so it shows it again but i need some more bugs to fix and others after i make this because im using chatgpt and some old userscripts so it may be buggy and im still in school so im going to make a project on this.

§
Posted: 19.12.2024.
Edited: 19.12.2024.

// ==UserScript== // @name KhanHack // @version 3.9 // @description Here is a Khan Academy Solver! // @author Logzilla6 // @match https://www.khanacademy.org/* // @grant none // @namespace https://greasyfork.org/users/783447 // ==/UserScript==

(function () { const overlayHTML = <div id="hackOverlay" style="position: fixed; top: 10px; right: 10px; background: #fff; padding: 15px; border: 2px solid #000; z-index: 9999;"> <button id="toggleBtn">Toggle</button> <h3>KhanHack</h3> <button id="resetAnswersBtn">Reset Answer List</button> <div id="ansBreak" style="max-height: 300px; overflow-y: auto;"> <h4>- Answers -</h4> </div> <small>Press 'M' to toggle menu visibility.</small> </div> ;

// Utility function to get elements by ID
function get(x) { return document.getElementById(x); }

// Reset the list of answers
function resetAnswers() {
    document.getElementById('ansBreak').innerHTML = ''; // Clear the answer list
    curAns = 1; // Reset the answer counter
    console.log('Answer list has been reset.');
}

// Error handling function
function handleFetchError(error) {
    console.error('An error occurred:', error);
    alert('An error occurred. Please check the console for details.');
}

// Add the overlay HTML to the page
let overlay = document.createElement("div");
overlay.innerHTML = overlayHTML;
document.body.appendChild(overlay);

// Toggle the visibility of the answer panel
let toggleBtn = get('toggleBtn');
let ansPanel = get('hackOverlay');
toggleBtn.onclick = function () {
    ansPanel.style.display = ansPanel.style.display === 'none' ? 'block' : 'none';
};

// Toggle panel visibility when pressing 'M' key
document.addEventListener('keydown', (event) => {
    if (event.key === 'm' || event.key === 'M') {
        ansPanel.style.display = ansPanel.style.display === 'none' ? 'block' : 'none';
    }
});

// Add the reset answers button functionality
let resetBtn = get('resetAnswersBtn');
resetBtn.onclick = resetAnswers;

'use strict';
window.loaded = false;

// Class to handle different types of answers
class Answer {
    constructor(answer, type) {
        this.body = answer;
        this.type = type;
    }

    // Check if the answer is multiple choice
    get isMultiChoice() {
        return this.type === "multiple_choice";
    }

    // Check if the answer is free response
    get isFreeResponse() {
        return this.type === "free_response";
    }

    // Check if the answer is an expression
    get isExpression() {
        return this.type === "expression";
    }

    // Check if the answer is a dropdown
    get isDropdown() {
        return this.type === "dropdown";
    }

    log() {
        try {
            const answer = this.body;
            answer.forEach(ans => {
                if (typeof ans === "string") {
                    // Handle potential "web+graphie" strings by replacing them or processing
                    if (ans.includes("web+graphie")) {
                        this.body[this.body.indexOf(ans)] = ""; // Clear the value
                        this.printImage(ans); // You may need to define `printImage`
                    } else {
                        answer[answer.indexOf(ans)] = ans.replace(/\$/g, ''); // Replace '$' signs
                    }
                }
            });
        } catch (error) {
            handleFetchError(error);
        }
    }
}

const originalFetch = window.fetch;

// Overriding the window.fetch method
window.fetch = function () {
    return originalFetch.apply(this, arguments).then(async (res) => {
        try {
            if (res.url.includes("/getAssessmentItem")) {
                const clone = res.clone();
                const json = await clone.json();
                let item, question;

                item = json.data.assessmentItem.item.itemData;
                question = JSON.parse(item).question;

                // Debugging: Log question structure
                console.log('Question structure:', question);

                Object.keys(question.widgets).forEach(widgetName => {
                    console.log('Processing widget:', widgetName); // Log widget name
                    switch (widgetName.split(" ")[0]) {
                        case "numeric-input":
                            freeResponseAnswerFrom(question).log();
                            break;
                        case "radio":
                            multipleChoiceAnswerFrom(question).log();
                            break;
                        case "expression":
                            expressionAnswerFrom(question).log();
                            break;
                        case "dropdown":
                            dropdownAnswerFrom(question).log();
                            break;
                        default:
                            console.warn('Unhandled widget type:', widgetName);
                    }
                });
            }

            if (!window.loaded) {
                console.clear();
                window.loaded = true;
            }

            return res;
        } catch (error) {
            handleFetchError(error);
            return res;
        }
    });
}

let curAns = 1;

// Extract free response answers from the question
function freeResponseAnswerFrom(question) {
    const answer = Object.values(question.widgets).flatMap((widget) => {
        if (widget.options?.answers) {
            console.log('Free response widget:', widget); // Log widget data
            return widget.options.answers
                .filter(answer => answer.status === "correct")
                .map(answer => {
                    let createPar = document.createElement('section');
                    createPar.innerHTML = answer.value;
                    document.getElementById('ansBreak').append(createPar);
                    curAns++;
                    return answer.value;
                });
        }
        return [];
    });

    return new Answer(answer, "free_response");
}

// Extract multiple choice answers from the question
function multipleChoiceAnswerFrom(question) {
    const answer = Object.values(question.widgets).flatMap((widget) => {
        if (widget.options?.choices) {
            console.log('Multiple choice widget:', widget); // Log widget data
            return widget.options.choices
                .filter(choice => choice.correct)
                .map(choice => {
                    let createPar = document.createElement('section');
                    createPar.innerHTML = choice.content;
                    document.getElementById('ansBreak').append(createPar);
                    curAns++;
                    return choice.content;
                });
        }
        return [];
    });

    return new Answer(answer, "multiple_choice");
}

// Extract expression answers from the question
function expressionAnswerFrom(question) {
    const answer = Object.values(question.widgets).flatMap((widget) => {
        if (widget.options?.answerForms) {
            console.log('Expression widget:', widget); // Log widget data
            return widget.options.answerForms
                .filter(answer => Object.values(answer).includes("correct"))
                .map(answer => {
                    let createPar = document.createElement('section');
                    createPar.innerHTML = answer.value;
                    document.getElementById('ansBreak').append(createPar);
                    curAns++;
                    return answer.value;
                });
        }
        return [];
    });

    return new Answer(answer, "expression");
}

// Extract dropdown answers from the question
function dropdownAnswerFrom(question) {
    const answer = Object.values(question.widgets).flatMap((widget) => {
        if (widget.options?.choices) {
            console.log('Dropdown widget:', widget); // Log widget data
            return widget.options.choices
                .filter(choice => choice.correct)
                .map(choice => {
                    let createPar = document.createElement('section');
                    createPar.innerHTML = choice.content;
                    document.getElementById('ansBreak').append(createPar);
                    curAns++;
                    return choice.content;
                });
        }
        return [];
    });

    return new Answer(answer, "dropdown");
}

})();

Post reply

Sign in to post a reply.