Last active
April 8, 2025 18:27
-
-
Save icebob/b662bd73f28816a1716dab0844814a09 to your computer and use it in GitHub Desktop.
TamperMonkey helper scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function htmlToNode(html) { | |
const template = document.createElement('template'); | |
template.innerHTML = html; | |
const nNodes = template.content.childNodes.length; | |
if (nNodes !== 1) { | |
throw new Error( | |
`html parameter must represent a single node; got ${nNodes}. ` + | |
'Note that leading or trailing spaces around an element in your ' + | |
'HTML, like " <img/> ", get parsed as text nodes neighbouring ' + | |
'the element; call .trim() on your input to avoid this.' | |
); | |
} | |
return template.content.firstChild; | |
} | |
function downloadBlob(filename, blob) { | |
const url = window.URL.createObjectURL(blob); | |
const link = document.createElement("a"); | |
link.href = url; | |
link.setAttribute("download", filename); | |
document.body.appendChild(link); | |
link.click(); | |
} | |
function querySelectorIncludesText (selector, text){ | |
return Array.from(document.querySelectorAll(selector)) | |
.filter(el => el.textContent.includes(text)); | |
} | |
function findClosestParent (startElement, fn) { | |
var parent = startElement.parentElement; | |
if (!parent) return undefined; | |
return fn(parent) ? parent : findClosestParent(parent, fn); | |
} | |
function xhrPatcher(xhr, patches) { | |
async function doPatch(x) { | |
if (x.__tmPatched) return; | |
for (const patch of patches) { | |
if (!patch.match || patch.match(x.__tmUrl, x.__tmMethod, x.__tmData, x)) { | |
if (patch.readyState == null || patch.readyState == x.readyState) { | |
const res = await patch.patch(x.response, x.responseType, x); | |
if (res !== undefined) { | |
Object.defineProperty(x, 'response', { writable: true }); | |
x.response = res; | |
if (typeof res == "string") { | |
Object.defineProperty(x, 'responseText', { writable: true }); | |
x.responseText = res; | |
} | |
} | |
x.__tmPatched = true; | |
} | |
//console.log(`Monkey patched ${x.__tmMethod} ${x.__tmUrl}:`, x.response); | |
} | |
} | |
} | |
const originalAddEventListener = xhr.addEventListener; | |
xhr.addEventListener = function(type, listener, options) { | |
if (type == 'readystatechange') { | |
var patchedListener = async function(event) { | |
doPatch(this); | |
listener.call(this, event); | |
}; | |
originalAddEventListener.call(this, type, patchedListener, options); | |
this.__tmListenerPatched = true; | |
} else { | |
originalAddEventListener.call(this, type, listener, options); | |
} | |
}; | |
var originalOpen = xhr.open; | |
xhr.open = function (method, url) { | |
this.__tmUrl = url; | |
this.__tmMethod = method; | |
return originalOpen.apply(this, arguments); | |
}; | |
// Capture request before any network activity occurs: | |
var originalSend = xhr.send; | |
xhr.send = function(data) { | |
this.__tmData = data; | |
if (this.onreadystatechange) { | |
var originalRSC = this.onreadystatechange; | |
if (originalRSC) { | |
// "onreadystatechange" exists. Monkey-patch it | |
this.onreadystatechange = async function() { | |
//console.log("onreadystatechange", this); | |
await doPatch(this); | |
return originalRSC.apply(this, arguments); | |
}; | |
} | |
} else if (!this.__tmListenerPatched) { | |
this.addEventListener("readystatechange", function() {}); | |
} | |
var originalLoad = this.onload; | |
if (originalLoad) { | |
// "onload" exists. Monkey-patch it | |
this.onload = async function() { | |
//console.log("onload", this); | |
await doPatch(this); | |
return originalLoad.apply(this, arguments); | |
}; | |
} | |
return originalSend.apply(this, arguments); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example 1