Base64 Link Decoder for 4chan and Archives

Decode base64-encoded links in 4chan posts and various archives

< 脚本 Base64 Link Decoder for 4chan and Archives 的反馈

提问 / 留言

§
发布于:2025-06-21

(function() {
    'use strict';

    const base64Regex = /^[A-Za-z0-9+/]{20,}={0,2}$/;

    const isURL = (str) => {
        try {
            return /^https?:\/\//i.test(str);
        } catch (e) {
            return false;
        }
    };

    function decodeAndReplace(element) {
        let content = element.innerHTML;

        const lines = content.split(/<br\s*\/?>/i);

        for (let i = 0; i < lines.length; i++) {
            lines[i] = lines[i].replace(/<wbr>/g, '');

            if (base64Regex.test(lines[i])) {
                try {
                    const decoded = atob(lines[i]);

                    if (decoded.includes('http')) {
                        const urls = decoded.split(/[\n\r\s]+/).filter(url => isURL(url));

                        if (urls.length > 0) {
                            lines[i] = urls.map(url => `<a href="${url}" target="_blank">${url}</a>`).join('<br>');
                        } else if (isURL(decoded)) {
                            lines[i] = `<a href="${decoded}" target="_blank">${decoded}</a>`;
                        }
                    } else if (isURL(decoded)) {
                        lines[i] = `<a href="${decoded}" target="_blank">${decoded}</a>`;
                    }
                } catch (e) {
                }
            } else {
                const parts = lines[i].split(/\s+/);
                for (let j = 0; j < parts.length; j++) {
                    if (base64Regex.test(parts[j])) {
                        try {
                            const decoded = atob(parts[j]);

                            if (decoded.includes('http')) {
                                const urls = decoded.split(/[\n\r\s]+/).filter(url => isURL(url));

                                if (urls.length > 0) {
                                    parts[j] = urls.map(url => `<a href="${url}" target="_blank">${url}</a>`).join('<br>');
                                } else if (isURL(decoded)) {
                                    parts[j] = `<a href="${decoded}" target="_blank">${decoded}</a>`;
                                }
                            } else if (isURL(decoded)) {
                                parts[j] = `<a href="${decoded}" target="_blank">${decoded}</a>`;
                            }
                        } catch (e) {
                        }
                    }
                }
                lines[i] = parts.join(' ');
            }
        }

        element.innerHTML = lines.join('<br>');
    }

    function processNewPosts() {
        const posts = document.querySelectorAll('.postMessage');
        posts.forEach(decodeAndReplace);

        const archivePosts = document.querySelectorAll('.text');
        archivePosts.forEach(decodeAndReplace);
    }

    function initScript() {
        console.log("Base64 Link Decoder initialized");

        processNewPosts();

        const observer = new MutationObserver((mutations) => {
            let shouldProcess = false;

            mutations.forEach((mutation) => {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            if (node.classList && (
                                node.classList.contains('postContainer') ||
                                node.querySelector('.postMessage')
                            )) {
                                shouldProcess = true;
                            }
                            if (node.classList && (
                                node.classList.contains('post') ||
                                node.querySelector('.text')
                            )) {
                                shouldProcess = true;
                            }
                        }
                    });
                }
            });

            if (shouldProcess) {
                processNewPosts();
            }
        });

        observer.observe(document.body, { childList: true, subtree: true });

        setInterval(processNewPosts, 10000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initScript);
    } else {
        initScript();
    }
})();

I will updated

发布留言

登录(不可用)以发布留言。

长期地址
遇到问题?请前往 GitHub 提 Issues。