您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Decode base64-encoded links in 4chan posts and various archives
// ==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(); } })();