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();