Greasy Fork is available in English.

Add Encode / Decode Button for Voz

Add encode / decode hex, base64 button for Voz

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Add Encode / Decode Button for Voz
// @namespace    0x4076696e63766e
// @version      0.7
// @description  Add encode / decode hex, base64 button for Voz
// @author       0x4076696e63766e
// @match        https://voz.vn/t/*
// @grant        none
// @license      GPL-3.0
// ==/UserScript==
/*
 * Regex - Decode Script from https://greasyfork.org/en/scripts/504506-decode-hex-strings-on-voz
 */
(function () {
    'use strict';

    var $Editor = null;
    var $BBMode = false;
    function openDialog(encodeFunc, isDecode) {
        const input = prompt("Nhập vào văn bản để mã hóa:");
        if (input === null) return; // Người dùng đã hủy
        if(isDecode){
          var decoded = null;
          if(input.match(/\b([0-9A-Fa-f]{2}\s*){4,}\b/g)) decoded = decodeHex(input)
          if(input.match(/(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})/g)) decoded = decodeBase64(input)
          openPopup(decoded);
          return;
        }
        const encoded = encodeFunc(input);
        pickEditor();
        if ($Editor) {
            if($Editor.tagName.toString() === 'DIV'){
              $Editor.innerHTML += `<p>${encoded}</p>`;
            }else{
              $Editor.value += `\n${encoded}`;
            }
        }
    }
    function openPopup(decoded){
      const newDiv = document.createElement(`div`);
      newDiv.className = "overlay-container is-active";
      newDiv.innerHTML = `
        <div class="overlay" tabindex="-1" role="dialog" aria-hidden="false">
          <div class="overlay-title">
            <a class="overlay-titleCloser js-overlayClose" role="button" tabindex="0" aria-label="Close"></a>
            😤
          </div>
          <div class="overlay-content">
            <div class="block-container">
		          <div class="block-body">
                <textarea class="input" style="min-height: 100px; max-height: 602px; padding: 10px 20px 20px; break-word; resize: none; height: 100px;">${decoded}</textarea>
              </div>
            </div>
          </div>
        </div>
      `
      document.body.appendChild(newDiv);
      const closeButton = newDiv.querySelector('.js-overlayClose');
      closeButton.addEventListener('click', () => {
          document.body.removeChild(newDiv);
      });
    }
    function decodeHex(hexString) {
        hexString = hexString.replace(/\s+/g, '');
        if (!/^[0-9A-Fa-f]{2,}$/.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));
            }
            if (/^[\x20-\x7E]*$/.test(hexStr) && hexStr.length > 3) {
                return hexStr;
            } else {
                return 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);
            if (/^[\x20-\x7E]*$/.test(binaryString) && binaryString.length > 3) {
                return binaryString;
            } else {
                return base64String;
            }
        } catch {
            return base64String;
        }
    }
    function hexEncode(str) {
        return Array.from(str).map(char => char.charCodeAt(0).toString(16).padStart(2, '0')).join('');
    }

    function base64Encode(str) {
        return btoa(unescape(encodeURIComponent(str)));
    }

    function pickEditor() {
        const editorContainers = document.querySelectorAll('div.message-editorWrapper');
        editorContainers.forEach(container => {
            const textareaEditor = container.querySelector('textarea.input');
            const bbEditor = container.querySelector('div.fr-element');
            const bbCodeMode = container.querySelector('#xfBbCode-1');
            if(bbCodeMode) $BBMode = bbCodeMode.classList.contains('fr-active')
            $Editor = ($BBMode) ? textareaEditor : bbEditor
        });
    }

    function createButton(label, callback) {
        const button = document.createElement('div');
        button.className = 'button--primary button';
        button.style.marginRight = '5px';
        button.textContent = label;
        button.onclick = callback;
        return button;
    }

    function insertHelper(extraDivs) {
        if (document.querySelectorAll("div.encode-helper").length > 0) return;

        extraDivs.forEach(extraDiv => {
            const newDiv = document.createElement('div');
            newDiv.className = 'formButtonGroup encode-helper';
            newDiv.appendChild(createButton('Hex', () => openDialog(hexEncode)));
            newDiv.appendChild(createButton('Base64', () => openDialog(base64Encode)));
            newDiv.appendChild(createButton('Decode', () => openDialog(null, true)));
            extraDiv.parentNode.insertBefore(newDiv, extraDiv.nextSibling);
        });
    }

    function main() {
        const elements = document.querySelectorAll('div.formButtonGroup');
        insertHelper(elements);
    }

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

    document.readyState === 'loading'
        ? document.addEventListener('DOMContentLoaded', initializeObserver)
        : initializeObserver();
})();