Skip to content

Instantly share code, notes, and snippets.

@istrueuser
Forked from busybox11/twitterblue-nerd.js
Last active April 22, 2023 19:31
Show Gist options
  • Save istrueuser/89b2fb7f203a7de028e8a77c35fd46f8 to your computer and use it in GitHub Desktop.
Save istrueuser/89b2fb7f203a7de028e8a77c35fd46f8 to your computer and use it in GitHub Desktop.
Red for 8$, Purple for verified 8$
// ==UserScript==
// @name @istrueuser Twitter Blue Red - twitter.com
// @namespace Violentmonkey Scripts
// @match *://*.twitter.com/*
// @grant none
// @version 1.8.0
// @author @istrueuser - trueuser.tk
// @description 4/3/2023, 6:11:21 PM
// @updateURL https://gist.githubusercontent.com/istrueuser/89b2fb7f203a7de028e8a77c35fd46f8/raw/twitterblue-nerd.js
// @downloadURL https://gist.githubusercontent.com/istrueuser/89b2fb7f203a7de028e8a77c35fd46f8/raw/twitterblue-nerd.js
// ==/UserScript==
// ORIGINAL BY @chaoticvibing - GH @busybox11
// FORKED FROM https://gist.githubusercontent.com/busybox11/53c76f57a577a47a19fab649a76f18e3/raw/twitterblue-nerd.js
// DONATE TO ORIGINAL AUTHOR https://paypal.me/busybox11
// DONATE TO FORK CREATOR https://paypal.me/istrueuser
const nerdtick = `
<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" fill="#EE4B2B"></path></g>
`
let regularVerifiedPath = 'svg 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"]'
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" fill="#1D9BF0"></path></g>`
const redtick = `
<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" fill="#BF40BF"></path></g>
`
let otherRegularVerifiedPath = 'svg path[d^="M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816zM9.662 14.85l-3.429-3.428 1.293-1.302 2.072 2.072 4.4-4.794 1.347 1.246z"]'
// STOLEN FROM https://stackoverflow.com/questions/70507318/how-to-get-react-element-props-from-html-element-with-javascript
function getReactProps(parent, target) {
parent = parent.wrappedJSObject ?? parent;
target = target.wrappedJSObject ?? 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 && props.isVerified) {
elem.setAttribute('viewBox', '0 0 24 24')
elem.innerHTML = redtick
} else if (props.isBlueVerified) {
elem.setAttribute('viewBox', '0 0 24 24')
elem.innerHTML = nerdtick
} else {
elem.setAttribute('viewBox', '0 0 24 24')
elem.innerHTML = regulartick
}
}
function bluetickHandling(bluetick) {
let propsElem = getReactProps(bluetick.parentElement, bluetick)
if (propsElem.children !== undefined) {
const props = propsElem.children[0][0].props
if (props.isBlueVerified !== undefined) {
updateBlueTick(bluetick, props)
} else {
// VERY HACKY FIX DO BETTER NEXT TIME
const otherProps = propsElem.children[0][propsElem.children[0].length - 1].props
updateBlueTick(bluetick, otherProps)
}
} else {
const propsElemParent = getReactProps(bluetick.parentElement.parentElement.parentElement, bluetick.parentElement.parentElement)
const propsParent = propsElemParent.children[0][0].props
updateBlueTick(bluetick, propsParent)
}
}
function bluetickHandling(bluetick) {
let propsElem = getReactProps(bluetick.parentElement.parentElement, bluetick.parentElement)
if (propsElem.children !== undefined) {
let props;
try {
props = propsElem.children[0][0].props
} catch(e) {
propsElem = getReactProps(bluetick.parentElement.parentElement.parentElement.parentElement, bluetick.parentElement.parentElement.parentElement)
props = propsElem.children[0][0].props
sc.log(props)
}
if (props.isBlueVerified !== undefined) {
updateBlueTick(bluetick, props)
} else {
const otherProps = propsElem.children[0][propsElem.children[0].length - 1].props
updateBlueTick(bluetick, otherProps)
}
} else {
const propsElemParent = getReactProps(bluetick.parentElement.parentElement.parentElement, bluetick.parentElement.parentElement)
const propsParent = propsElemParent.children[0][0].props
updateBlueTick(bluetick, propsParent)
}
}
function handleMutation(mutations) {
try {
for (let mutation of mutations) {
for (let elem of mutation.addedNodes) {
// SVG PATH DETECTION
// Thanks GH @artesea - https://gist.github.com/busybox11/53c76f57a577a47a19fab649a76f18e3?permalink_comment_id=4366043#gistcomment-4366043
// Author of this snippet
let blueticksPath = elem.querySelectorAll(regularVerifiedPath)
let differentBlueticksPath = elem.querySelectorAll(otherRegularVerifiedPath)
const blueTicks = [
...blueticksPath,
...differentBlueticksPath
]
for (let bluetick of blueTicks.flat()) {
try {
if (bluetick !== null) {
bluetickHandling(bluetick.parentElement.parentElement)
}
} catch(e) {sc.log("blueTicks check", bluetick, e)}
}
// PROFILE POPUPS
const profileBlueticks = elem.querySelectorAll('.css-1dbjc4n.r-xoduu5.r-1pcd2l5')
try {
for (let profileBluetick of profileBlueticks) {
if (profileBluetick !== null) {
if (profileBluetick.lastChild.firstChild.innerText.includes('Twitter Blue')) {
updateBlueTick(profileBluetick.firstChild, {isBlueVerified: true, isVerified: false})
}
}
}
} catch(e) {sc.log(e)}
}
}
} catch(e) {sc.log(e)}
}
const sc = {
log: (...args) => {
console.log('[nerdtick]', ...args)
}
}
const observer = new MutationObserver(handleMutation)
observer.observe(document, { childList: true, subtree: true })
@INeedTogepi
Copy link

I would like to suggest adding fill="#1D9BF0" to the regulartick SVG data. That way it would make anyone using dark mode consistently see blue checkmarks instead of white ones for actual verified accounts.

Also, I noticed that if I click on a red checkmark profile in the "You Might Like" section to the right on profile pages, when it loads the red checkmark profile it shows the default-colored checkmark (white for dark mode, blue for light mode). If I refresh the page, it then correctly shows a red checkmark.

@lewisje
Copy link

lewisje commented Apr 3, 2023

The correct update and download URLs are https://gist.githubusercontent.com/istrueuser/89b2fb7f203a7de028e8a77c35fd46f8/raw/twitterblue-nerd.js without the version-component between the raw and the twitterblue-nerd.js.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment