Skip to content

Instantly share code, notes, and snippets.

@waxpancake
Forked from busybox11/twitterblue-nerd.js
Last active November 10, 2022 02:24
Show Gist options
  • Save waxpancake/0abb39e04f053a0fc989c8ade720fb09 to your computer and use it in GitHub Desktop.
Save waxpancake/0abb39e04f053a0fc989c8ade720fb09 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name @chaoticvibing Twitter Blue Clown - twitter.com
// @namespace Violentmonkey Scripts
// @match *://*.twitter.com/*
// @grant none
// @version 1.1.2
// @author @chaoticvibing - GH @busybox11
// @description 11/9/2022, 18:45:28 PM
// @updateURL https://gist.github.com/waxpancake/0abb39e04f053a0fc989c8ade720fb09
// @downloadURL https://gist.github.com/waxpancake/0abb39e04f053a0fc989c8ade720fb09
// ==/UserScript==
/*
* DISCLAIMER
* I made this in a rush because of a challenge I convinced myself to do in reply to a tweet:
* https://twitter.com/Quinten0508/status/1590464705822224384?s=20&t=R_KhoR4a-_3fI4n4mbmmGA
* It might have horrible performance and it could not be reliable as I've tested this very quickly
* on some places I could find Twitter blue checkmarks, but I haven't made much research on it.
* At least it runs fine on my Ryzen 9 5900HS laptop and I don't see any noticeable frame drops
* on my 165Hz QHD display since I made this script, which might be a sign it's not impacting much.
* (I don't care anyway, fell free to modify it if it isn't)
*/
// 1.1.0 ALSO UPDATE ON HEADER OF PROFILE
// 1.1.1 AUTO UPDATE
// 1.1.2 CHANGED TO CLOWN ICON BY @WAXPANCAKE
// STOLEN FROM https://twitter.com/shadowbIood/status/1590462560515473409?s=20&t=AmfQmmFgdpKOsPqnoawjVQ
const clowntick = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
<circle fill="#4289C1" cx="29" cy="3" r="2"/><circle fill="#4289C1" cx="33" cy="8" r="3"/><circle fill="#4289C1" cx="33" cy="4" r="3"/>
<circle fill="#4289C1" cx="7" cy="3" r="2"/><circle fill="#4289C1" cx="3" cy="8" r="3"/><circle fill="#4289C1" cx="3" cy="4" r="3"/>
<path fill="#FEE7B8" d="M36 18c0 9.941-8.059 18-18 18S0 27.941 0 18 8.059 0 18 0s18 8.059 18 18"/>
<circle fill="#4289C1" cx="30.5" cy="4.5" r="2.5"/><circle fill="#4289C1" cx="32" cy="7" r="2"/>
<circle fill="#4289C1" cx="5.5" cy="4.5" r="2.5"/><circle fill="#4289C1" cx="4" cy="7" r="2"/>
<circle fill="#FF7892" cx="6.93" cy="21" r="4"/><circle fill="#FF7892" cx="28.93" cy="21" r="4"/>
<path fill="#DA2F47" d="M27.335 23.629c-.178-.161-.444-.171-.635-.029-.039.029-3.922 2.9-8.7 2.9-4.766 0-8.662-2.871-8.7-2.9-.191-.142-.457-.13-.635.029-.177.16-.217.424-.094.628C8.7 24.472 11.788 31 18 31s9.301-6.528 9.429-6.743c.123-.205.084-.468-.094-.628z"/>
<ellipse fill="#664500" cx="11.5" cy="11.5" rx="2.5" ry="3.5"/>
<ellipse fill="#664500" cx="25.5" cy="11.5" rx="2.5" ry="3.5"/><circle fill="#BB1A34" cx="18.5" cy="19.5" r="3.5"/>
</svg>
`
const regulartick = `
<g><path d="M22.25 12c0-1.43-.88-2.67-2.19-3.34.46-1.39.2-2.9-.81-3.91s-2.52-1.27-3.91-.81c-.66-1.31-1.91-2.19-3.34-2.19s-2.67.88-3.33 2.19c-1.4-.46-2.91-.2-3.92.81s-1.26 2.52-.8 3.91c-1.31.67-2.2 1.91-2.2 3.34s.89 2.67 2.2 3.34c-.46 1.39-.21 2.9.8 3.91s2.52 1.26 3.91.81c.67 1.31 1.91 2.19 3.34 2.19s2.68-.88 3.34-2.19c1.39.45 2.9.2 3.91-.81s1.27-2.52.81-3.91c1.31-.67 2.19-1.91 2.19-3.34zm-11.71 4.2L6.8 12.46l1.41-1.42 2.26 2.26 4.8-5.23 1.47 1.36-6.2 6.77z"></path></g>
`
// STOLEN FROM https://stackoverflow.com/questions/70507318/how-to-get-react-element-props-from-html-element-with-javascript
function getReactProps(parent, target) {
const keyof_ReactProps = Object.keys(parent).find(k => k.startsWith("__reactProps$"));
const symof_ReactFragment = Symbol.for("react.fragment");
//Find the path from target to parent
let path = [];
let elem = target;
while (elem !== parent) {
let index = 0;
for (let sibling = elem; sibling != null;) {
if (sibling[keyof_ReactProps]) index++;
sibling = sibling.previousElementSibling;
}
path.push({ child: elem, index });
elem = elem.parentElement;
}
//Walk down the path to find the react state props
let state = elem[keyof_ReactProps];
for (let i = path.length - 1; i >= 0 && state != null; i--) {
//Find the target child state index
let childStateIndex = 0, childElemIndex = 0;
while (childStateIndex < state.children.length) {
let childState = state.children[childStateIndex];
if (childState instanceof Object) {
//Fragment children are inlined in the parent DOM element
let isFragment = childState.type === symof_ReactFragment && childState.props.children.length;
childElemIndex += isFragment ? childState.props.children.length : 1;
if (childElemIndex === path[i].index) break;
}
childStateIndex++;
}
let childState = state.children[childStateIndex] ?? (childStateIndex === 0 ? state.children : null);
state = childState?.props;
elem = path[i].child;
}
return state;
}
function updateBlueTick(elem, props) {
if (props.isBlueVerified) {
elem.setAttribute('viewBox', '0 0 96 96')
elem.innerHTML = clowntick
} else {
elem.setAttribute('viewBox', '0 0 24 24')
elem.innerHTML = regulartick
}
}
function handleMutation(mutations) {
try {
for (mutation of mutations) {
for (elem of mutation.addedNodes) {
const blueticks = elem.querySelectorAll('[aria-label="Verified account"]')
for (bluetick of blueticks) {
if (bluetick !== null) {
const propsElem = getReactProps(bluetick.parentElement, bluetick)
if (propsElem.children !== undefined) {
const props = propsElem.children[0][0].props
updateBlueTick(bluetick, props)
} else {
const propsElemParent = getReactProps(bluetick.parentElement.parentElement.parentElement, bluetick.parentElement.parentElement)
const propsParent = propsElemParent.children[0][0].props
updateBlueTick(bluetick, propsParent)
}
}
}
}
}
} catch(e) {console.log(e)}
}
const observer = new MutationObserver(handleMutation)
observer.observe(document, { childList: true, subtree: true })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment