Created
October 13, 2025 01:00
-
-
Save itslukej/12d326dd9c87b081ff96d36da1c7a520 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Imgur.com → Imgur.lol | |
| // @namespace https://luke.gg/ | |
| // @version 1.3 | |
| // @description i.imgur.com -> imgur.lol | |
| // @author luke | |
| // @match *://*/* | |
| // @run-at document-start | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| const OLD_DOMAIN = /i\.(imgur\.com)/gi; | |
| const NEW_DOMAIN = 'imgur.lol'; | |
| /** ---- Stage 1: Early interception for preloaded elements ---- **/ | |
| // Override common URL-creating functions | |
| const origCreateElement = Document.prototype.createElement; | |
| Document.prototype.createElement = function(tag) { | |
| const el = origCreateElement.call(this, tag); | |
| const observer = new MutationObserver(() => rewriteAttributes(el)); | |
| observer.observe(el, { attributes: true }); | |
| return el; | |
| }; | |
| // Rewrite all URL-like attributes of an element | |
| function rewriteAttributes(node) { | |
| if (!node || !node.attributes) return; | |
| for (const attr of node.attributes) { | |
| if (typeof attr.value === 'string' && attr.value.includes('imgur.com')) { | |
| const newVal = attr.value.replace(OLD_DOMAIN, NEW_DOMAIN); | |
| if (newVal !== attr.value) node.setAttribute(attr.name, newVal); | |
| } | |
| } | |
| } | |
| /** ---- Stage 2: Text & Attribute replacement after DOM loads ---- **/ | |
| function rewriteAll(root=document.body) { | |
| if (!root) return; | |
| // Elements | |
| const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT); | |
| while (walker.nextNode()) rewriteAttributes(walker.currentNode); | |
| // Text nodes | |
| const textWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT); | |
| while (textWalker.nextNode()) { | |
| const node = textWalker.currentNode; | |
| if (node.nodeValue.includes('imgur.com')) { | |
| node.nodeValue = node.nodeValue.replace(OLD_DOMAIN, NEW_DOMAIN); | |
| } | |
| } | |
| } | |
| /** ---- Stage 3: Dynamic mutation observer ---- **/ | |
| const mo = new MutationObserver(muts => { | |
| for (const m of muts) { | |
| for (const node of m.addedNodes) { | |
| if (node.nodeType === 1) { // element | |
| rewriteAll(node); | |
| } else if (node.nodeType === 3) { // text | |
| if (node.nodeValue.includes('imgur.com')) { | |
| node.nodeValue = node.nodeValue.replace(OLD_DOMAIN, NEW_DOMAIN); | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| /** ---- Stage 4: Apply once DOM is ready ---- **/ | |
| function init() { | |
| rewriteAll(); | |
| mo.observe(document.body, { childList: true, subtree: true }); | |
| } | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', init); | |
| } else { | |
| init(); | |
| } | |
| /** ---- Stage 5: Intercept navigation clicks ---- **/ | |
| document.addEventListener('click', ev => { | |
| const a = ev.target.closest('a[href]'); | |
| if (a && a.href.includes('imgur.com')) { | |
| a.href = a.href.replace(OLD_DOMAIN, NEW_DOMAIN); | |
| } | |
| }, true); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment