// TODO: Sidestep race condition in a less patchwork manner setTimeout(function(){ renderBypass(); /* TODO: Check if it actually went through */ }, 1250); function renderBypass() { // Setup page elements //Get Katex CSS var katex_css = document.createElement('link'); katex_css.setAttribute('rel','stylesheet'); katex_css.setAttribute('href','https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css '); document.head.appendChild(katex_css); // Get the webpage data, devoid of any headers or cookies. Acts as if the user is not logged in at all. doFetch(window.location).then(data => { processData(data); }) } function processData(data){ // Clear the "hidden explanation" out and replace it with a blank explanation area. // The innermost item is ".s1i7awl8" document.querySelector('main .mwhvwas').innerHTML = '

Explanation

'; var expArea = document.querySelector('.sladerBypass .s1i7awl8') // Render new stuff // Is this an abomination? Yes. // Does it work? Also yes. // // ... // // I don't want to talk about it. // var json = data.match(/(?<=window.Quizlet\["(questionDetailsPageData|textbookExercisePageData)"] = ).+?(?=; QLoad\("Quizlet.(questionDetailsPageData|textbookExercisePageData)")/gm); if (!json) { // Display ratelimit message expArea.innerHTML = `

You have been ratelimited by Quizlet


Try clearing your cookies for Quizlet and reloading this page, this usually fixes it.
— Slader Bypass.
`; } // Parse JSON data var qDetails = JSON.parse(json[0]); var solutions = (qDetails.question || qDetails.exercise).solutions; // Display JSON data as answer solutions.forEach(solution => { const numSteps = solution.steps.length; solution.steps.forEach(step => { const stepNum = step.stepNumber; // Create card element var div = document.createElement('div'); // Insert boilerplate card data div.innerHTML = '

'; // Step X: .s39tzu2 div.querySelector('.s39tzu2').textContent = (numSteps === stepNum) ? "Result" : "Step " + stepNum; // x of x: .sb9ch1t div.querySelector('.sb9ch1t').textContent = stepNum + ' of ' + numSteps; // I'm not 100% on the structure of these, but I'll take a stab at it. // It seems that only one column is ever used. I'll iterate anyways, because I can't trust that. step.columns.forEach(column => { var columnDiv = document.createElement('div'); // Insert inner text if (column.text) { var textDiv = document.createElement('div'); textDiv.classList.add('sladerBypassKatexTextArea') textDiv.textContent = column.text.replaceAll('\n\n\n', '\n\n'); // The replace call is a bit funky but it works. columnDiv.appendChild(textDiv); } // Insert image, if applicable if (column.images.additional) { var image = document.createElement('img'); image.setAttribute('src', column.images.additional.regular.srcUrl); columnDiv.appendChild(image); } // Append server-rendered image src url. Used in errorhandling. (See: handleKatexError()) if (column.images.latex && column.images.latex.large) { div.querySelector('.sladerBypassKatex').setAttribute('katexsrc', column.images.latex.large.srcUrl); } div.querySelector('.sladerBypassKatex').appendChild(columnDiv); }); // Append card to explanation area. expArea.appendChild(div); }); }); // Render Katex for each card expArea.querySelectorAll('.sladerBypassKatex').forEach(textArea => { try { renderMathInElement(textArea, { delimiters: [ {left: "$$", right: "$$", display: true}, {left: "$", right: "$", display: false}, {left: "\\(", right: "\\)", display: false}, {left: "\\begin{equation}", right: "\\end{equation}", display: true}, {left: "\\begin{align}", right: "\\end{align}", display: true}, {left: "\\begin{alignat}", right: "\\end{alignat}", display: true}, {left: "\\begin{gather}", right: "\\end{gather}", display: true}, {left: "\\begin{CD}", right: "\\end{CD}", display: true}, {left: "\\[", right: "\\]", display: true} ], throwOnError : true, errorCallback : function(a, b){ handleKatexError(a, b, textArea); } }); } catch (error) { console.error('Katex experienced an error. Attempting to load image replacement.'); } }); }; function handleKatexError(a, b, textArea) { // Display Katex error console.error(a); console.error(b); // Remove broken Katex textArea.querySelector('.sladerBypassKatexTextArea').innerHTML = ''; // Fallback to server-rendered katex (I'm assuming they have better error detection there.) var image = document.createElement('img'); image.setAttribute('src', textArea.getAttribute('katexsrc')); textArea.appendChild(image); } async function doFetch(url) { const response = await fetch(url, { method: 'GET', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'omit', // include, *same-origin, omit headers: { }, redirect: 'follow', // manual, *follow, error referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url body: null // body data type must match "Content-Type" header }); return response.text(); }