NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name arca/sm decoder // @author keut // @version 230713190109 // @updateURL https://openuserjs.org/meta/keut/arcasm_decoder.meta.js // @downloadURL https://openuserjs.org/install/keut/arcasm_decoder.user.js // @match https://arca.live/b/* // @grant GM_registerMenuCommand // @run-at document-start // @license MIT // ==/UserScript== var toSolidBytes = (_, p1) => String.fromCharCode(parseInt(p1, 16)); var encode = (str) => { const iso8859 = encodeURIComponent(str).replace( /%([0-9A-F]{2})/g, toSolidBytes ); return btoa(iso8859); }; var escape = (ch) => `%${("0" + ch.charCodeAt(0).toString(16)).slice(-2)}`; var decode = (str) => { try { return decodeURIComponent(atob(str).split("").map(escape).join("")); } catch { return; } }; var textDecode = (str) => { const decoded = decode(str.replace(/=+$/, "")); if (!decoded) { return; } const hasControl = decoded.match(/[\x00-\x08\x0e-\x1f\x7f-\xff]/); if (hasControl) { return; } return decoded; }; var padInsensitiveRegex = /(?<=^|[^A-Za-z0-9+/])(?:[A-Za-z0-9+/]{4}){2,}(?:[A-Za-z0-9+/]{2,3})?(?:=+|(?=[^A-Za-z0-9+/])|$)/g; var isUrl = (url) => { try { new URL(url); return true; } catch { return false; } }; var createAnchor = (url) => { const anchor = document.createElement("a"); anchor.href = url; anchor.target = "_blank"; anchor.textContent = url; return anchor; }; var storageAttributeName = "data-encoded"; var createSpanForRecovery = (range) => { const div = document.createElement("div"); div.append(range.extractContents()); const html = div.innerHTML; const span = document.createElement("span"); span.setAttribute(storageAttributeName, html); return span; }; var wrapIfLink = (maybeUrl) => { return isUrl(maybeUrl) ? createAnchor(maybeUrl) : document.createTextNode(maybeUrl); }; var replaceRange = (range, text) => { const span = createSpanForRecovery(range); range.deleteContents(); const node = wrapIfLink(text); range.insertNode(node); range.surroundContents(span); }; var findNodeByOffset = (walker, count, isInclusive = false) => { let start = 0; while (true) { const node = walker.currentNode; const end = start + node.textContent.length; if (count < end || isInclusive && count === end) { return { node, offset: count - start }; } start = end; if (!walker.nextNode()) { return; } } }; var getEndZeroRange = (root) => { const range = new Range(); range.setStart(root, root.childNodes.length); range.setEnd(root, root.childNodes.length); return range; }; var getRange = (root, targetText) => { const start = root.textContent.indexOf(targetText); if (start === -1) { return; } const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT); walker.nextNode(); const anchor = findNodeByOffset(walker, start); if (!anchor) { return; } const end = targetText.length + anchor.offset; const focus = findNodeByOffset(walker, end, true); if (!focus) { return; } const range = new Range(); range.setStart(anchor.node, anchor.offset); range.setEnd(focus.node, focus.offset); return range; }; var getBlockAncestor = (element) => { const majorBlockRegex = /^(?:blockquote|body|div|form|h\\d|li|main|ol|p|pre|section|table|ul)/i; let cursor = element; while (!cursor.tagName.match(majorBlockRegex)) { cursor = cursor.parentElement; } return cursor; }; var replaceByString = (element, match) => { const decoded = textDecode(match); if (!decoded) { return false; } const matchRange = getRange(element, match) || getEndZeroRange(element); replaceRange(matchRange, decoded); return true; }; var getThisOrParentElement = (target) => { if (target.nodeType === target.ELEMENT_NODE) { return target; } return target.parentElement ?? void 0; }; var decodeSelection = (selection) => { const draggedText = `${selection}`.replace(/\s+/g, ""); if (!draggedText) { return; } const decoded = textDecode(draggedText); if (!decoded) { return; } const canCoincidence = draggedText.length < 12 && /^([\d ]+|[a-z ]+)$/i.test(draggedText); if (canCoincidence) { return; } const range = selection.getRangeAt(0); const element = getThisOrParentElement(range.commonAncestorContainer); replaceByString(element, draggedText); selection.collapseToEnd(); }; var getModifiableBlock = (target) => { const element = getThisOrParentElement(target); if (!element) { return; } const isNonsense = element.tagName.match(/^(A|INPUT|TEXTAREA)$/) || element.isContentEditable; const block = getBlockAncestor(element); const hasInput = !!block.querySelector?.("textarea,[contenteditable]"); if (isNonsense || hasInput) { return; } return block; }; var decodeElementContent = (element) => { const matches = element.innerText?.match(padInsensitiveRegex); if (!matches) { return false; } return matches.map((match) => replaceByString(element, match)).some(Boolean); }; var tryDecodeBase64 = (event) => { const selection = event.view?.getSelection?.(); if (selection?.toString?.()) { const block = selection.getRangeAt(0)?.commonAncestorContainer; if (block && getModifiableBlock(block)) { decodeSelection(selection); } return false; } const target = event.target; const element = getModifiableBlock(target); return element ? decodeElementContent(element) : false; }; var isDecoded = false; var mouseHandler = (event) => { if (event.type === "click") { isDecoded = tryDecodeBase64(event); } else { const canWordSelect = event.detail >= 2; if (canWordSelect && isDecoded) { event.preventDefault(); } } }; var hookPointer = (document2) => { document2.body.addEventListener("click", mouseHandler); document2.body.addEventListener("mousedown", mouseHandler); }; var getParentElement = (node) => { return node instanceof HTMLElement ? node : node?.parentElement; }; var encodeAndPaste = (document2, text) => { const encoded = encode(text); const input = document2.activeElement; if (input.selectionStart != null) { const text2 = input.value; const head = text2.slice(0, input.selectionStart); const tail = text2.slice(input.selectionEnd); input.value = `${head}${encoded}${tail}`; return true; } if (getParentElement(getSelection().anchorNode)?.isContentEditable) { replaceRange(getSelection().getRangeAt(0), encoded); getSelection().collapseToEnd(); return true; } return false; }; var hookPaste = (document2) => { const capture = { capture: true }; let isShiftPressed = false; const recordShiftPress = (event) => { isShiftPressed = event.shiftKey; }; document2.body.addEventListener("keydown", recordShiftPress, capture); document2.body.addEventListener("keyup", recordShiftPress, capture); const handlePaste = (event) => { if (!isShiftPressed) { return; } const text = event.clipboardData?.getData?.("text/plain"); if (!text) { return; } if (encodeAndPaste(document2, text)) { event.stopImmediatePropagation(); event.preventDefault(); } }; document2.body.addEventListener("paste", handlePaste, capture); }; var supressAgree = (document2) => { document2.cookie = "allow_sensitive_media=true"; }; var waitAnimationFrame = async (window2) => { let id = 0; await new Promise((resolve) => { id = window2.requestAnimationFrame(resolve); }); window2.cancelAnimationFrame(id); }; var hookPage = async (window2) => { const { document: document2 } = window2; supressAgree(document2); while (!document2.body) { await waitAnimationFrame(window2); } hookPointer(document2); hookPaste(document2); }; var decodeAll = () => { decodeElementContent(document.body); }; var restoreAll = () => { const spans = document.querySelectorAll(`[${storageAttributeName}]`); for (const span of spans) { const html = span.getAttribute(storageAttributeName); if (html) { span.outerHTML = html; } } }; var registerMenuCommand = () => { GM_registerMenuCommand("Decode all", decodeAll, "D"); GM_registerMenuCommand("Restore all", restoreAll, "R"); }; hookPage(window); registerMenuCommand();