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);
}
}
})();