// ==UserScript== // @name Unlock locked steps in Symbolab [BROKEN] // @namespace http://*.symbolab.com/* // @version 1.1 // @description unlocks locked symbolab step-by-step instructions by overwriting XMLHttpRequest // @author joseph // @match *://*.symbolab.com/* // @grant none // @downloadURL none // ==/UserScript== (function(open) { var patched = 0; function patchResponseLoop(obj) { for (var k in obj) { if (typeof obj[k] == "object" && obj[k] !== null) { patchResponseLoop(obj[k]); } else { if (k == "isLocked") { obj[k] = false; console.log("[patcher] patched a symbolab isLocked property"); patched++; } } } } var open_prototype = XMLHttpRequest.prototype.open, intercept_response = function(urlpattern, callback) { XMLHttpRequest.prototype.open = function() { arguments['1'].match(urlpattern) && this.addEventListener('readystatechange', function(event) { if ( this.readyState === 4 ) { var response = callback(event.target.responseText); // allow intercepted responses to be written to Object.defineProperty(this, 'response', {writable: true}); Object.defineProperty(this, 'responseText', {writable: true}); this.response = this.responseText = response; } }); return open_prototype.apply(this, arguments); }; }; intercept_response(/steps/i, function(response) { console.log("[patcher] intercept request, current RES ", JSON.parse(response)); var parsedO = JSON.parse(response); patchResponseLoop(parsedO); console.log("[patcher] === PATCHSET COMPLETE, enjoy ==="); document.getElementById("PlotLink").innerHTML = "Unlocked " + patched + " step(s)!"; return JSON.stringify(parsedO); }); })(XMLHttpRequest.prototype.open);