Last active
January 1, 2025 15:55
-
-
Save narze/4b33764266c4d99625d15309e073aa5b to your computer and use it in GitHub Desktop.
Arc Boost - Hide Facebook Notification Bubble
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
(function () { | |
'use strict'; | |
const enabled = true; | |
function log() { | |
// Uncomment to debug | |
// console.log(arguments) | |
} | |
function findNotificationBubble() { | |
// Step 1: Find all potential notification elements | |
// Facebook specific | |
const allElements = document.querySelectorAll('[role="navigation"] div, [role="navigation"] span, [role="navigation"] a'); | |
// const allElements = document.querySelectorAll('div, span, a'); | |
for (const el of allElements) { | |
const style = window.getComputedStyle(el); | |
const text = el.textContent.trim(); | |
// Check visibility and size constraints | |
if ( | |
style.display !== 'none' && | |
style.visibility !== 'hidden' && | |
el.offsetParent !== null | |
) { | |
const width = el.offsetWidth; | |
const height = el.offsetHeight; | |
// Threshold for notification bubble size (e.g., max 24px) | |
if ( | |
width > 0 && width <= 24 && | |
height > 0 && height <= 24 && | |
/^\d+$/.test(text) // Check if content is numeric | |
) { | |
// Check if the bubble is red-ish or blue-ish | |
console.log(`π Found unread notification bubble: ${text}`, el); | |
return el; | |
} | |
} | |
} | |
log('β No unread notification bubble detected.'); | |
return null; | |
} | |
/** π₯ Detect if color is red-ish or blue-ish **/ | |
function isColorRedOrBlue(color) { | |
const rgb = getRGBFromColor(color); | |
if (!rgb) return false; // If we can't parse the color, return false | |
const [r, g, b] = rgb; | |
if (r === 29 && g === 155 && b === 240) { | |
return true; | |
} | |
// Define thresholds for red and blue | |
const isRed = r > 100 && r > b && g < 50; // More red than blue/green | |
const isBlue = b > 100 && b > r && g < 50; // More blue than red/green | |
return isRed || isBlue; | |
} | |
/** π¨ Convert color to RGB array **/ | |
function getRGBFromColor(color) { | |
if (!color) return null; | |
let rgb; | |
// Handle RGB and rgba (including cases where alpha channel is used) | |
if (color.startsWith('rgb')) { | |
rgb = color.match(/\d+/g); | |
} | |
// Handle hex color format | |
else if (color.startsWith('#')) { | |
if (color.length === 7) { | |
rgb = [ | |
parseInt(color.slice(1, 3), 16), | |
parseInt(color.slice(3, 5), 16), | |
parseInt(color.slice(5, 7), 16) | |
]; | |
} | |
} | |
return rgb ? rgb.map(Number) : null; | |
} | |
function findNotificationBubbleParentAndChild() { | |
// Step 2: Detect the bubble | |
const bubble = findNotificationBubble(); | |
if (!bubble) return null; | |
let currentElement = bubble; | |
// Traverse upward to find a parent that's reasonably larger | |
while (currentElement.parentElement) { | |
currentElement = currentElement.parentElement; | |
const parentWidth = currentElement.offsetWidth; | |
const parentHeight = currentElement.offsetHeight; | |
// Threshold for a reasonable parent size (>24px) | |
if (parentWidth > 24 && parentHeight > 24) { | |
log('β Found parent container:', currentElement); | |
// Step 3: Find child smaller than 24px | |
const children = currentElement.querySelectorAll('*'); | |
for (const child of children) { | |
const childWidth = child.offsetWidth; | |
const childHeight = child.offsetHeight; | |
if (childWidth > 0 && childWidth <= 24 && childHeight > 0 && childHeight <= 24) { | |
log('π― Found child smaller than 24px:', child); | |
return child; | |
} | |
} | |
log('β No child smaller than 24px found in this parent.'); | |
return null; | |
} | |
} | |
log('β No suitable parent container found.'); | |
return null; | |
} | |
// Main function to hide notification bubbles | |
function hideNotificationBubbles() { | |
const bubble = findNotificationBubbleParentAndChild(); | |
if (!bubble) { | |
log('β No notification bubbles found to hide.'); | |
return; | |
} | |
bubble.style.display = 'none'; | |
} | |
function observeDOMChanges() { | |
const observer = new MutationObserver((mutationsList) => { | |
for (const mutation of mutationsList) { | |
if (mutation.addedNodes.length > 0) { | |
hideNotificationBubbles(); | |
} | |
} | |
}); | |
if (document.body) { | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true, | |
}); | |
log('π DOM Observer started, watching for notification bubbles...'); | |
} else { | |
setTimeout(observeDOMChanges, 500); | |
return; | |
} | |
} | |
if (enabled) { | |
hideNotificationBubbles(); | |
observeDOMChanges(); | |
} | |
/** π Remove Numbers from Page Title **/ | |
function cleanPageTitle() { | |
const originalTitle = document.title; | |
const cleanTitle = originalTitle.replace(/^\(\d+\)\s*/, ''); | |
if (originalTitle !== cleanTitle) { | |
document.title = cleanTitle; | |
log(`π Cleaned page title: "${cleanTitle}"`); | |
} | |
} | |
/** π― Observe Title Changes **/ | |
function observeTitleChanges() { | |
// Ensure the title element is available | |
const titleElement = document.querySelector('title'); | |
if (!titleElement) { | |
log('β No <title> element found, retrying...'); | |
setTimeout(observeTitleChanges, 500); | |
return; | |
} | |
const titleObserver = new MutationObserver(() => { | |
cleanPageTitle(); | |
}); | |
titleObserver.observe(titleElement, { | |
childList: true, | |
subtree: true, | |
}); | |
log('π Title Observer started, watching for title changes...'); | |
} | |
if (enabled) { | |
cleanPageTitle() | |
observeTitleChanges() | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment