Decode Hex strings on Voz

Decode Hex, Base64

As of 2024-08-22. See the latest version.

// ==UserScript==
// @name         Decode Hex strings on Voz
// @namespace    Decode Hex strings on Voz
// @version      2.0
// @icon         https://www.google.com/s2/favicons?sz=64&domain=voz.vn
// @author       kylyte
// @description  Decode Hex, Base64
// @match        https://voz.vn/t/*
// @run-at       document-idle
// @license      GPL-3.0
// ==/UserScript==

(function() {
    'use strict';

    function decodeHex(hexString) {
        if (!/^[0-9A-Fa-f]+$/.test(hexString)) return hexString;
        let hexStr = '';
        try {
            for (let i = 0; i < hexString.length; i += 2) {
                hexStr += String.fromCharCode(parseInt(hexString.substr(i, 2), 16));
            }
            return /^[\w\s.,!?@#$%^&*()_+=[\]{}|;:'",<>\-\/`~]*$/.test(hexStr) ? hexStr : hexString;
        } catch {
            return hexString;
        }
    }

    function decodeBase64(base64String) {
        if (!/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test(base64String)) return base64String;
        try {
            let binaryString = atob(base64String);
            return /^[\w\s.,!?@#$%^&*()_+=[\]{}|;:'",<>\-\/`~]*$/.test(binaryString) ? binaryString : base64String;
        } catch {
            return base64String;
        }
    }

    function decodeContent(elements, regex, decodeFunc) {
        for (let element of elements) {
            if (element.classList.contains('decoded')) continue;
            let content = element.innerHTML;
            let matches = content.match(regex);
            if (matches) {
                matches.forEach(match => {
                    content = content.replace(new RegExp(escapeRegExp(match), 'g'), decodeFunc(match));
                });
                element.innerHTML = content;
                element.classList.add('decoded');
            }
        }
    }

    function escapeRegExp(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function main() {
        let elements = document.getElementsByClassName('bbCodeBlock-content');
        decodeContent(elements, /([0-9A-Fa-f]{2}){8,}/g, decodeHex);
        decodeContent(elements, /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/m, decodeBase64);
    }

    main();

    new MutationObserver(() => main()).observe(document.documentElement, {
        childList: true,
        subtree: true
    });
})();