Greasy Fork

Greasy Fork is available in English.

Base64 Link Decoder for 4chan and Archives

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Base64 Link Decoder for 4chan and Archives
// @match       *://boards.4channel.org/*
// @namespace TOTK
// @version 963.369
// @match       *://boards.4chan.org/*
// @match       *://archived.moe/*
// @license MIT
// @match       *://archiveofsins.com/*
// @grant       none
// @description Decode base64-encoded links in 4chan posts and various archives
// ==/UserScript==

(function() {
    'use strict';

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

    // Ist das eine URL? Schau mal!
    const isURL = (str) => {
        try {
            return /^https?:\/\//i.test(str);
        } catch (e) {
            return false;
        }
    };

    // Dekodieren und Links machen! Juhu!
    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>');
    }

    // Neue Posts checken! Hurra!
    function processNewPosts() {
        const posts = document.querySelectorAll('.postMessage');
        posts.forEach(decodeAndReplace);

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

    // Los geht's! Script starten!
    function initScript() {
        console.log("Base64 Decoder gestartet! Yeah!");

        processNewPosts();

        // Wie ein Spion beobachten!
        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 });

        // Alle 10 Sekunden gucken! Tick tack!
        setInterval(processNewPosts, 10000);
    }

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