NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @namespace https://openuserjs.org/users/DanielBlaze // @name Reddit Base64 Decoder // @description Automatically base64 decode links in reddit posts // @copyright 2018, DanielBlaze (https://openuserjs.org/users/DanielBlaze) // @updateURL https://openuserjs.org/meta/DanielBlaze/Reddit_Base64_Decoder.meta.js // @license MIT // @version 2.0.0 // @author DanielBlaze // @grant none // @match https://*.reddit.com/r/* // ==/UserScript== // ==OpenUserJS== // @author DanielBlaze // ==/OpenUserJS== /** * Wraps HTML in some styling to show its been decoded */ function decodedBlock(inner) { const css = [ 'border: 1px dashed #e6e6e6', 'padding: 10px', 'background-image: linear-gradient(45deg, rgba(199,199,199,.25) 25%, rgba(227,227,227,.25) 25%, rgba(227,227,227,.25) 50%, rgba(199,199,199,.25) 50%, rgba(199,199,199,.25) 75%, rgba(227,227,227,.25) 75%, rgba(227,227,227,.25) 100%)', 'background-size: 40px 40px' ]; return `<div style='${css.join(';')}'>${inner}</div>`; } /** * Attempts to decode an array of elements. Styling will be lost on any element which is decoded * @param {HTMLElement[]} domElements */ function decode(domElements) { // for all pararaph tags domElements.forEach(domElement => { // split on the words we find, and make sure we have something before continuing const words = domElement.innerText.split(' '); if (words.length === 0) return; // decode the string let changed = false; const transformed = words.map(word => { try { const decoded = atob(word); // if it's valid, change it if (decoded.includes('https://') || decoded.includes('http://')) { changed = true; return decodedBlock( decoded .replace(/[\r\n]+/g, '<br /><br />') .replace(/(https?:\/\/[^\s<]+)/g, `<a href="$1" style='text-decoration: underline #8989ff dotted; text-underline-offset: 2px;'>$1</a>`) ); } } catch (_) {} return word; }); // only if we changed something should we update the HTML - otherwise we lose the original formatting if (changed) domElement.innerHTML = transformed.join(' '); }); } (function () { 'use strict'; // check we have observers available to us if (!MutationObserver) return; // observer config - only interested in tree modifications const config = { childList: true, subtree: true }; // the callback to decode the string const callback = function (mutationsList, observer) { mutationsList.forEach(mutation => { if (mutation.target.nodeName === 'DIV' && mutation.addedNodes.length > 0) { // check we can find the post contents const postContents = mutation.target.querySelectorAll('p'); if (!postContents) return; // decode that bad boy decode(postContents); } }); }; // create an observer instance with the callback const observer = new MutationObserver(callback); // Start observing the target node for mutations observer.observe(document, config); // run on page load incase no mutations occur, but only on old reddit const postContainer = document.querySelector('.expando'); if (postContainer) { const postContents = postContainer.querySelectorAll('p'); if (postContents) { decode(postContents); } } })();