Created
April 6, 2025 03:17
-
-
Save scarf005/90faf4e2bbe0e61bc5c243e202921070 to your computer and use it in GitHub Desktop.
Replace thumbs-down with baps
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 GitHub Custom Thumbs Down | |
// @namespace https://github.com/scarf005 | |
// @version 1.0.0 | |
// @description Replaces the default GitHub thumbs down emoji with a custom image | |
// @author scarf | |
// @match https://github.com/* | |
// @grant none | |
// @run-at document-idle | |
// ==/UserScript== | |
(() => { | |
'use strict' | |
/** | |
* The URL of the custom emoji image | |
* Using size=20 to match GitHub's typical reaction emoji size | |
* @type {string} | |
*/ | |
const CUSTOM_EMOJI_URL = 'https://cdn.discordapp.com/emojis/885793151263068160.webp?size=20' | |
/** | |
* The CSS selector to find the GitHub thumbs down emoji elements | |
* Targets the <g-emoji> wrapper with the specific alias | |
* @type {string} | |
*/ | |
const THUMBS_DOWN_SELECTOR = 'g-emoji[alias="-1"]' | |
/** | |
* Updates a given emoji element (g-emoji) to use the custom image | |
* @param {Element} gEmojiElement - The <g-emoji> element to modify | |
* @returns {void} | |
*/ | |
const replaceEmojiElement = (gEmojiElement) => { | |
/** @type {HTMLImageElement | null} */ | |
const img = gEmojiElement.querySelector('img') | |
// Check if the image exists and hasn't already been replaced | |
if (img && img.src !== CUSTOM_EMOJI_URL) { | |
img.src = CUSTOM_EMOJI_URL | |
img.srcset = '' // Clear srcset to ensure our src is used | |
img.width = 20 // Ensure consistent size | |
img.height = 20 // Ensure consistent size | |
// Optional: Update fallback src on parent, though less critical | |
// gEmojiElement.setAttribute('fallback-src', CUSTOM_EMOJI_URL) | |
// console.log('Replaced thumbs down emoji:', img) // For debugging | |
} | |
} | |
/** | |
* Finds and replaces all thumbs down emojis within a given node or the entire document | |
* @param {Node} parentNode - The node to search within (defaults to document) | |
* @returns {void} | |
*/ | |
const replaceAllThumbsDown = (parentNode = document) => { | |
/** @type {NodeListOf<Element>} */ | |
const emojiElements = parentNode.querySelectorAll(THUMBS_DOWN_SELECTOR) | |
emojiElements.forEach(replaceEmojiElement) | |
} | |
/** | |
* Callback function for the MutationObserver | |
* Checks added nodes for relevant emoji elements | |
* @param {MutationRecord[]} mutationsList | |
* @param {MutationObserver} observer | |
* @returns {void} | |
*/ | |
const handleMutations = (mutationsList, observer) => { | |
mutationsList.forEach((mutation) => { | |
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { | |
mutation.addedNodes.forEach((node) => { | |
// Check if the added node is an element node | |
if (node.nodeType === Node.ELEMENT_NODE) { | |
/** @type {Element} */ | |
const element = node | |
// Check if the node itself is the target emoji | |
if (element.matches && element.matches(THUMBS_DOWN_SELECTOR)) { | |
replaceEmojiElement(element) | |
} | |
// Check if the node contains any target emojis (important for larger chunks of HTML) | |
// Use querySelectorAll on the element itself for efficiency | |
replaceAllThumbsDown(element) | |
} | |
}) | |
} | |
}) | |
} | |
// --- Main Execution --- | |
// 1. Initial replacement run for emojis present on page load | |
replaceAllThumbsDown(document.body) | |
// 2. Set up MutationObserver to watch for dynamically added content | |
/** @type {MutationObserverInit} */ | |
const observerConfig = { | |
childList: true, // Watch for addition/removal of children | |
subtree: true // Watch descendants as well | |
} | |
/** @type {MutationObserver} */ | |
const observer = new MutationObserver(handleMutations) | |
// 3. Start observing the document body | |
// Use document.body as it's generally available and containers change often on GitHub | |
if (document.body) { | |
observer.observe(document.body, observerConfig) | |
} else { | |
// Fallback if body isn't immediately ready (less likely with @run-at document-idle) | |
document.addEventListener('DOMContentLoaded', () => observer.observe(document.body, observerConfig)) | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment