帖子

  • b1xcy

    看到很多佬们都分享了自己的apikey,但很多都要多过一步base64 decode,感觉有点麻烦,就让ai跑了一个油猴一键解码并复制```
    // ==UserScript==
    // @name linux.do 选中文本 Base64 解码
    // @namespace https://linux.do/
    // @version 1.0.0
    // @description 在 linux.do 选中文本弹出的引用按钮栏中添加 Base64 解码按钮
    // @author b1xcy
    // @match https://linux.do/*
    // @grant none
    // @run-at document-idle
    // ==/UserScript==

    (function () {
    "use strict";

    const BUTTON_CLASS = "btn btn-icon-text btn-flat base64-decode";
    const BUTTON_MARKER = "data-base64-decode-btn";

    function getSelectedText() {
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0) return "";
    return selection.toString().trim();
    }

    function normalizeBase64(input) {
    let text = input
    .replace(/\s+/g, "")
    .replace(/-/g, "+")
    .replace(/_/g, "/");

    // 去掉常见包装,如 data:...;base64,xxxx
    const dataUrlMatch = text.match(/base64,(.+)$/i);
    if (dataUrlMatch) text = dataUrlMatch[1];

    // 去掉可能的引号
    text = text.replace(/^["']|["']$/g, "");

    // 补齐 padding
    const pad = text.length % 4;
    if (pad) text += "=".repeat(4 - pad);

    return text;
    }

    function decodeBase64(input) {
    const cleaned = normalizeBase64(input);
    if (!cleaned) {
    throw new Error("没有可解码的内容");
    }

    // atob 得到 binary string,再按 UTF-8 还原
    const binary = atob(cleaned);
    const bytes = Uint8Array.from(binary, (ch) => ch.charCodeAt(0));
    try {
    return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
    } catch (_) {
    // 回退:直接返回 latin1 字符串
    return binary;
    }
    }

    async function copyText(text) {
    try {
    if (navigator.clipboard && navigator.clipboard.writeText) {
    await navigator.clipboard.writeText(text);
    return true;
    }
    } catch (_) {
    // fall through
    }

    const ta = document.createElement("textarea");
    ta.value = text;
    ta.setAttribute("readonly", "");
    ta.style.cssText = "position:fixed;left:-9999px;top:-9999px;";
    document.body.appendChild(ta);
    ta.select();
    let ok = false;
    try {
    ok = document.execCommand("copy");
    } catch (_) {
    ok = false;
    }
    ta.remove();
    return ok;
    }

    function showResult(decoded, copied) {
    // 简单 toast,不依赖站点 UI
    let toast = document.getElementById("ld-base64-decode-toast");
    if (!toast) {
    toast = document.createElement("div");
    toast.id = "ld-base64-decode-toast";
    toast.style.cssText = [
    "position:fixed",
    "z-index:999999",
    "left:50%",
    "bottom:24px",
    "transform:translateX(-50%)",
    "max-width:min(720px,90vw)",
    "max-height:40vh",
    "overflow:auto",
    "padding:12px 14px",
    "border-radius:10px",
    "background:#1d1c1d",
    "color:#fff",
    "box-shadow:0 8px 24px rgba(0,0,0,.28)",
    "font:13px/1.5 system-ui,-apple-system,Segoe UI,Roboto,sans-serif",
    "white-space:pre-wrap",
    "word-break:break-word",
    "display:none",
    ].join(";");
    document.body.appendChild(toast);
    }

    const tip = copied ? "已复制到剪贴板" : "解码成功(复制失败,请手动复制)";
    toast.textContent = ${tip}\n\n${decoded};
    toast.style.display = "block";

    clearTimeout(showResult._timer);
    showResult._timer = setTimeout(() => {
    toast.style.display = "none";
    }, 5000);
    }

    function showError(message) {
    let toast = document.getElementById("ld-base64-decode-toast");
    if (!toast) {
    // 复用 showResult 的创建逻辑
    showResult("", false);
    toast = document.getElementById("ld-base64-decode-toast");
    }
    toast.textContent = Base64 解码失败:${message};
    toast.style.display = "block";
    clearTimeout(showResult._timer);
    showResult._timer = setTimeout(() => {
    toast.style.display = "none";
    }, 3000);
    }

    async function onDecodeClick(event) {
    event.preventDefault();
    event.stopPropagation();

    const selected = getSelectedText();
    if (!selected) {
    showError("请先选中一段文本");
    return;
    }

    try {
    const decoded = decodeBase64(selected);
    const copied = await copyText(decoded);
    showResult(decoded, copied);
    } catch (err) {
    showError(err && err.message ? err.message : "无效的 Base64 内容");
    }
    }

    function createDecodeButton() {
    const button = document.createElement("button");
    button.className = BUTTON_CLASS;
    button.type = "button";
    button.title = "Base64 解码";
    button.setAttribute(BUTTON_MARKER, "1");
    button.innerHTML = [
    '<svg class="fa d-icon d-icon-code svg-icon fa-width-auto svg-string" width="1em" height="1em" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">&#039;,
    '<use href="#code"></use>',
    "</svg>",
    ' <span class="d-button-label">Base64 解码</span>',
    ].join("");
    button.addEventListener("click", onDecodeClick);
    return button;
    }

    function injectButton(container) {
    if (!(container instanceof HTMLElement)) return;
    if (!container.classList.contains("buttons")) return;
    // 只处理包含引用相关按钮的弹出栏,避免误伤其它 .buttons
    if (
    !container.querySelector(".insert-quote, .copy-quote, .quote-button, button")
    ) {
    return;
    }
    if (container.querySelector([${BUTTON_MARKER}])) return;

    const btn = createDecodeButton();
    // 插到「复制引用」后面;没有就追加到末尾
    const copyBtn = container.querySelector(".copy-quote");
    if (copyBtn && copyBtn.parentNode === container) {
    copyBtn.insertAdjacentElement("afterend", btn);
    } else {
    container.appendChild(btn);
    }
    }

    function scan(root = document) {
    root.querySelectorAll?.(".buttons").forEach(injectButton);
    if (root instanceof HTMLElement && root.matches?.(".buttons")) {
    injectButton(root);
    }
    }

    // 初次扫描
    scan(document);

    // Discourse 是动态渲染,监听弹层出现
    const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
    if (!(node instanceof HTMLElement)) continue;
    scan(node);
    }
    }
    });

    observer.observe(document.documentElement, {
    childList: true,
    subtree: true,
    });
    })();
    ```代码无任何外带操作,可以放心用

    主楼
  • 西红柿炒番茄

    你们还要自己解码的吗,直接发给ai,让他测试,配置不就好了,我就负责重启

    #1

发表回复

登录后回复