changed observer callback

update names based on the element from the mutation event rather than checking the chatbox for unchecked messages each mutation
This commit is contained in:
zomo
2026-04-19 19:01:01 -05:00
parent 3b8c402873
commit 6218d6bad1
9 changed files with 272 additions and 165 deletions
+105 -62
View File
@@ -4,6 +4,7 @@
// @match https://www.twitch.tv/* // @match https://www.twitch.tv/*
// @version 0.1 // @version 0.1
// @runat document-end // @runat document-end
// @grant unsafeWindow
// @downloadURL https://git.zomo.dev/zomo/browser-scripts/raw/branch/main/dist/ttv-obfuscated-names.user.js // @downloadURL https://git.zomo.dev/zomo/browser-scripts/raw/branch/main/dist/ttv-obfuscated-names.user.js
// @supportURL https://git.zomo.dev/zomo/browser-scripts/issues // @supportURL https://git.zomo.dev/zomo/browser-scripts/issues
// @homepageURL https://git.zomo.dev/zomo/browser-scripts // @homepageURL https://git.zomo.dev/zomo/browser-scripts
@@ -31,6 +32,8 @@ var nameList = [
// image: 'personimage1', // image: 'personimage1',
// }, // },
] ]
var usernameExtraSuffix = nameConfig =>
nameConfig.nameCount > 0 ? `${nameConfig.nameCount + 1}` : ''
var { storedUsers, nameListUsed, nameListCount } = loadStoredUserData() var { storedUsers, nameListUsed, nameListCount } = loadStoredUserData()
function getStoredUser(name) { function getStoredUser(name) {
@@ -81,6 +84,16 @@ function loadStoredUserData() {
} }
} }
} }
function clearStoredUsers() {
localStorage.removeItem('obf-data')
storedUsers = {}
nameListUsed = {}
nameListCount = 0
}
unsafeWindow.obfClear = () => {
clearStoredUsers()
location.reload()
}
function getRandomName() { function getRandomName() {
const startingIndex = Math.round(Math.random() * (nameList.length - 1)) const startingIndex = Math.round(Math.random() * (nameList.length - 1))
let foundName = false let foundName = false
@@ -127,6 +140,7 @@ function obfuscator(chatMessage) {
if (ignoreMod && chatMessage.isMod) { if (ignoreMod && chatMessage.isMod) {
return null return null
} }
console.log(`[OBFUSCATOR] Updating Username: ${chatMessage.username}`)
chatMessage.username = chatMessage.username.toLowerCase() chatMessage.username = chatMessage.username.toLowerCase()
const userData = getStoredUser(chatMessage.username) const userData = getStoredUser(chatMessage.username)
if (userData !== null) { if (userData !== null) {
@@ -141,19 +155,17 @@ function innermostElement(elem) {
if (elem.children.length === 0) { if (elem.children.length === 0) {
return elem return elem
} }
return innermostElement(elem.children[0]) let child = elem.children[0]
return innermostElement(child)
} }
function usernameTemplateSuffix(newChatMessage) { function elementTreeFind(elem, fn) {
if (newChatMessage.nameCount === 0) { if (fn(elem)) {
return '' return elem
} }
return `${newChatMessage.nameCount}` if (!elem.parentElement) {
} return null
function usernameImageTemplateSuffix(newChatMessage) {
if (newChatMessage.nameCount === 0) {
return ''
} }
return `${newChatMessage.nameCount}` return elementTreeFind(elem.parentElement, fn)
} }
function loadChatMessage(chatboxMessage) { function loadChatMessage(chatboxMessage) {
@@ -166,15 +178,14 @@ function loadChatMessage(chatboxMessage) {
const chatboxBadgeContainer = chatboxMessage.querySelector( const chatboxBadgeContainer = chatboxMessage.querySelector(
'.chat-line__message--badges' '.chat-line__message--badges'
) )
if (!chatboxBadgeContainer) {
console.error("found message, couldn't find badges")
return
}
const chatboxUser = chatboxMessage.querySelector('.chat-line__username') const chatboxUser = chatboxMessage.querySelector('.chat-line__username')
if (!chatboxUser) { if (!chatboxUser) {
console.error("found message, couldn't find user") console.error("found message, couldn't find user")
return return
} }
if (chatboxUser.querySelector('.obf-name')) {
return
}
const chatboxUserInner = chatboxUser.querySelector( const chatboxUserInner = chatboxUser.querySelector(
'.chat-author__display-name' '.chat-author__display-name'
) )
@@ -182,19 +193,17 @@ function loadChatMessage(chatboxMessage) {
console.error("found message, couldn't find userInner") console.error("found message, couldn't find userInner")
return return
} }
chatboxMessage.classList.add('obf-loaded')
if (chatboxUser.classList.contains('seventv-paint')) {
chatboxUser.classList.remove('seventv-paint')
}
let isMod = false let isMod = false
for (const badge of chatboxBadgeContainer.children) { if (chatboxBadgeContainer) {
if ( for (const badge of chatboxBadgeContainer.children) {
badge.hasAttribute('data-badge') && if (
(badge.getAttribute('data-badge') === 'moderator' || badge.hasAttribute('data-badge') &&
badge.getAttribute('data-badge') === 'broadcaster') (badge.getAttribute('data-badge') === 'moderator' ||
) { badge.getAttribute('data-badge') === 'broadcaster')
isMod = true ) {
chatboxMessage.classList.add('ismod') isMod = true
chatboxMessage.classList.add('ismod')
}
} }
} }
const chatMessage = { const chatMessage = {
@@ -203,7 +212,7 @@ function loadChatMessage(chatboxMessage) {
} }
const newChatMessage = obfuscator(chatMessage) const newChatMessage = obfuscator(chatMessage)
if (newChatMessage !== null) { if (newChatMessage !== null) {
setUsernameDetails(newChatMessage, chatboxUserInner, chatboxUser) setUsernameDetails(newChatMessage, chatboxUserInner, true)
} }
loadReplyLine(chatboxMessage) loadReplyLine(chatboxMessage)
loadMessageMentions(chatboxMessage) loadMessageMentions(chatboxMessage)
@@ -214,24 +223,30 @@ function loadReplyLine(chatboxMessage) {
if (!replyUsername) { if (!replyUsername) {
return return
} }
if (replyUsername.querySelector('.obf-name')) {
return
}
const chatMessage = { const chatMessage = {
username: replyUsername.textContent.replace(/^@/, ''), username: replyUsername.textContent.replace(/^@/, ''),
isMod: false, isMod: false,
} }
const newChatMessage = obfuscator(chatMessage) const newChatMessage = obfuscator(chatMessage)
if (newChatMessage !== null) { if (newChatMessage !== null) {
setUsernameDetails(newChatMessage, replyUsername, void 0, '@') setUsernameDetails(newChatMessage, replyUsername, false, '@')
} }
} }
function loadMessageMentions(chatboxMessage) { function loadMessageMentions(chatboxMessage) {
function eachMention(messageMention) { function eachMention(messageMention) {
if (messageMention.querySelector('.obf-name')) {
return
}
const chatMessage = { const chatMessage = {
username: messageMention.textContent.replace(/^@/, ''), username: messageMention.textContent.replace(/^@/, ''),
isMod: false, isMod: false,
} }
const newChatMessage = obfuscator(chatMessage) const newChatMessage = obfuscator(chatMessage)
if (newChatMessage !== null) { if (newChatMessage !== null) {
setUsernameDetails(newChatMessage, messageMention, void 0, '@') setUsernameDetails(newChatMessage, messageMention, false, '@')
} }
} }
const messageMentions = chatboxMessage.querySelectorAll( const messageMentions = chatboxMessage.querySelectorAll(
@@ -244,8 +259,10 @@ function loadMessageMentions(chatboxMessage) {
function loadAdditionalUserNames(chatboxMessage) { function loadAdditionalUserNames(chatboxMessage) {
const chatterNames = chatboxMessage.querySelectorAll('.chatter-name') const chatterNames = chatboxMessage.querySelectorAll('.chatter-name')
for (const chatterName of chatterNames) { for (const chatterName of chatterNames) {
chatboxMessage.classList.add('obf-loaded')
const chatterNameBox = innermostElement(chatterName) const chatterNameBox = innermostElement(chatterName)
if (chatterNameBox.querySelector('.obf-name')) {
continue
}
const username = chatterNameBox.textContent const username = chatterNameBox.textContent
if (!username) { if (!username) {
continue continue
@@ -260,53 +277,72 @@ function loadAdditionalUserNames(chatboxMessage) {
} }
} }
} }
function setUsernameDetails(newChatMessage, textbox, colorbox, prefixStr = '') { function setUsernameDetails(
const username = `${newChatMessage.username}${usernameTemplateSuffix(newChatMessage)}` newChatMessage,
usernamebox,
doColor = false,
prefix = ''
) {
const suffix = usernameExtraSuffix(newChatMessage)
const username = `${newChatMessage.username}${suffix}`
const container = document.createElement('span')
container.classList.add('obf-name')
const imageName = newChatMessage.image const imageName = newChatMessage.image
if (imageName) { if (imageName) {
const image = nameImages[imageName] const image = nameImages[imageName]
const img = document.createElement('img') const imgElem = document.createElement('img')
img.classList.add('obf-image', 'ffz--pointer-events', 'ffz-tooltip') imgElem.classList.add('obf-image', 'ffz--pointer-events', 'ffz-tooltip')
img.setAttribute('data-tooltip-type', 'html') imgElem.setAttribute('data-tooltip-type', 'html')
img.setAttribute('data-title', username) imgElem.setAttribute('data-title', username)
img.setAttribute('alt', username) imgElem.setAttribute('alt', username)
img.setAttribute('src', image) imgElem.setAttribute('src', image)
const prefix = document.createElement('span') const prefixElem = document.createElement('span')
prefix.textContent = prefixStr prefixElem.textContent = prefix
const suffix = document.createElement('span') const suffixElem = document.createElement('span')
suffix.textContent = usernameImageTemplateSuffix(newChatMessage) suffixElem.textContent = suffix
textbox.replaceChildren(prefix, img, suffix) container.replaceChildren(prefixElem, imgElem, suffixElem)
} else { } else {
textbox.textContent = `${prefixStr}${username}` container.textContent = `${prefix}${username}`
} }
if (colorbox) { if (doColor) {
colorbox.style.color = newChatMessage.color container.style.color = newChatMessage.color
}
usernamebox.replaceChildren(container)
}
function eachMutation(record) {
const target = record.target
if (target.classList.contains('chat-scrollable-area__message-container')) {
for (const target2 of record.addedNodes) {
eachMutationTarget(record, target2)
}
} else {
eachMutationTarget(record, record.target)
} }
} }
function eachMutationTarget(record, target) {
var OBSERVER_RATE_LIMIT = 1 const chatboxMessage = elementTreeFind(
var observerLastRun = 0 target,
function observerCallback() { elem =>
if (Date.now() - observerLastRun < OBSERVER_RATE_LIMIT) { elem.parentElement?.classList.contains(
return 'chat-scrollable-area__message-container'
} ) || false
observerLastRun = Date.now()
const chatbox = document.querySelector(
'.chat-scrollable-area__message-container'
) )
const chatboxMessages = Array.from(chatbox?.children ?? []) if (chatboxMessage) {
for (const chatboxMessage of chatboxMessages) { console.warn('[OBFUSCATOR] mutated message', chatboxMessage, record)
if (chatboxMessage.classList.contains('obf-loaded')) {
continue
}
loadChatMessage(chatboxMessage) loadChatMessage(chatboxMessage)
loadAdditionalUserNames(chatboxMessage) loadAdditionalUserNames(chatboxMessage)
} }
} }
var observer = new MutationObserver(observerCallback)
var observer = new MutationObserver(mutationRecords => {
for (const record of mutationRecords) {
eachMutation(record)
}
})
observer.observe(document, { attributes: true, childList: true, subtree: true }) observer.observe(document, { attributes: true, childList: true, subtree: true })
var styleAddition = document.createElement('style') var styleAddition = document.createElement('style')
styleAddition.innerHTML = ` styleAddition.innerHTML = `
/* hide badges, except broadcaster and moderator */
.chat-line__message--badges { .chat-line__message--badges {
display: none; display: none;
} }
@@ -321,10 +357,17 @@ styleAddition.innerHTML = `
display: inline-block; display: inline-block;
} }
/* disable 7tv paint colors */
.seventv-paint { .seventv-paint {
background-image: none !important; background-image: none !important;
} }
/* disable username translations */
.chat-author__intl-login {
display: none;
}
/* style image when used as name */
img.obf-image { img.obf-image {
vertical-align: middle; vertical-align: middle;
margin: -0.5rem 0; margin: -0.5rem 0;
+90 -52
View File
@@ -1,13 +1,8 @@
import { obfuscator } from './obfuscator' import { obfuscator } from './obfuscator'
import { NameConfigInstance, nameImages } from './options' import { NameConfigInstance, nameImages, usernameExtraSuffix } from './options'
import { import { ChatMessage, elementTreeFind, innermostElement } from './util'
ChatMessage,
innermostElement,
usernameImageTemplateSuffix,
usernameTemplateSuffix,
} from './util'
export function loadChatMessage(chatboxMessage: Element) { function loadChatMessage(chatboxMessage: Element) {
// only chat messages // only chat messages
const chatboxMessageInner = chatboxMessage.querySelector( const chatboxMessageInner = chatboxMessage.querySelector(
'.chat-line__message' '.chat-line__message'
@@ -20,10 +15,6 @@ export function loadChatMessage(chatboxMessage: Element) {
const chatboxBadgeContainer = chatboxMessage.querySelector<HTMLSpanElement>( const chatboxBadgeContainer = chatboxMessage.querySelector<HTMLSpanElement>(
'.chat-line__message--badges' '.chat-line__message--badges'
) )
if (!chatboxBadgeContainer) {
console.error("found message, couldn't find badges")
return
}
const chatboxUser = chatboxMessage.querySelector<HTMLSpanElement>( const chatboxUser = chatboxMessage.querySelector<HTMLSpanElement>(
'.chat-line__username' '.chat-line__username'
@@ -33,6 +24,11 @@ export function loadChatMessage(chatboxMessage: Element) {
return return
} }
// already applied username
if (chatboxUser.querySelector('.obf-name')) {
return
}
const chatboxUserInner = chatboxUser.querySelector<HTMLSpanElement>( const chatboxUserInner = chatboxUser.querySelector<HTMLSpanElement>(
'.chat-author__display-name' '.chat-author__display-name'
) )
@@ -41,24 +37,18 @@ export function loadChatMessage(chatboxMessage: Element) {
return return
} }
// got the data, so we're loaded
chatboxMessage.classList.add('obf-loaded')
// hide 7tv extra colors
if (chatboxUser.classList.contains('seventv-paint')) {
chatboxUser.classList.remove('seventv-paint')
}
// check if mod // check if mod
let isMod = false let isMod = false
for (const badge of chatboxBadgeContainer.children) { if (chatboxBadgeContainer) {
if ( for (const badge of chatboxBadgeContainer.children) {
badge.hasAttribute('data-badge') && if (
(badge.getAttribute('data-badge') === 'moderator' || badge.hasAttribute('data-badge') &&
badge.getAttribute('data-badge') === 'broadcaster') (badge.getAttribute('data-badge') === 'moderator' ||
) { badge.getAttribute('data-badge') === 'broadcaster')
isMod = true ) {
chatboxMessage.classList.add('ismod') isMod = true
chatboxMessage.classList.add('ismod')
}
} }
} }
@@ -72,7 +62,7 @@ export function loadChatMessage(chatboxMessage: Element) {
const newChatMessage = obfuscator(chatMessage) const newChatMessage = obfuscator(chatMessage)
if (newChatMessage !== null) { if (newChatMessage !== null) {
setUsernameDetails(newChatMessage, chatboxUserInner, chatboxUser) setUsernameDetails(newChatMessage, chatboxUserInner, true)
} }
loadReplyLine(chatboxMessage) loadReplyLine(chatboxMessage)
@@ -89,6 +79,11 @@ function loadReplyLine(chatboxMessage: Element) {
return return
} }
// already applied username
if (replyUsername.querySelector('.obf-name')) {
return
}
const chatMessage: ChatMessage = { const chatMessage: ChatMessage = {
username: replyUsername.textContent.replace(/^@/, ''), username: replyUsername.textContent.replace(/^@/, ''),
isMod: false, isMod: false,
@@ -98,12 +93,17 @@ function loadReplyLine(chatboxMessage: Element) {
const newChatMessage = obfuscator(chatMessage) const newChatMessage = obfuscator(chatMessage)
if (newChatMessage !== null) { if (newChatMessage !== null) {
setUsernameDetails(newChatMessage, replyUsername, undefined, '@') setUsernameDetails(newChatMessage, replyUsername, false, '@')
} }
} }
function loadMessageMentions(chatboxMessage: Element) { function loadMessageMentions(chatboxMessage: Element) {
function eachMention(messageMention: HTMLElement) { function eachMention(messageMention: HTMLElement) {
// already applied username
if (messageMention.querySelector('.obf-name')) {
return
}
const chatMessage: ChatMessage = { const chatMessage: ChatMessage = {
username: messageMention.textContent.replace(/^@/, ''), username: messageMention.textContent.replace(/^@/, ''),
isMod: false, isMod: false,
@@ -113,7 +113,7 @@ function loadMessageMentions(chatboxMessage: Element) {
const newChatMessage = obfuscator(chatMessage) const newChatMessage = obfuscator(chatMessage)
if (newChatMessage !== null) { if (newChatMessage !== null) {
setUsernameDetails(newChatMessage, messageMention, undefined, '@') setUsernameDetails(newChatMessage, messageMention, false, '@')
} }
} }
@@ -126,15 +126,21 @@ function loadMessageMentions(chatboxMessage: Element) {
} }
} }
export function loadAdditionalUserNames(chatboxMessage: Element) { function loadAdditionalUserNames(chatboxMessage: Element) {
// look for additional chat member names // look for additional chat member names
const chatterNames = const chatterNames =
chatboxMessage.querySelectorAll<HTMLElement>('.chatter-name') chatboxMessage.querySelectorAll<HTMLElement>('.chatter-name')
for (const chatterName of chatterNames) { for (const chatterName of chatterNames) {
chatboxMessage.classList.add('obf-loaded') const chatterNameBox = innermostElement<HTMLElement, HTMLElement>(
chatterName
)
// already applied username
if (chatterNameBox.querySelector('.obf-name')) {
continue
}
const chatterNameBox = innermostElement(chatterName)
const username = chatterNameBox.textContent const username = chatterNameBox.textContent
if (!username) { if (!username) {
continue continue
@@ -157,37 +163,69 @@ export function loadAdditionalUserNames(chatboxMessage: Element) {
function setUsernameDetails( function setUsernameDetails(
newChatMessage: NameConfigInstance, newChatMessage: NameConfigInstance,
textbox: HTMLElement, usernamebox: HTMLElement,
colorbox?: HTMLElement, doColor = false,
prefixStr: string = '' prefix: string = ''
) { ) {
const username = `${newChatMessage.username}${usernameTemplateSuffix(newChatMessage)}` const suffix = usernameExtraSuffix(newChatMessage)
const username = `${newChatMessage.username}${suffix}`
const container = document.createElement('span')
container.classList.add('obf-name')
const imageName = newChatMessage.image const imageName = newChatMessage.image
if (imageName) { if (imageName) {
// image name // image name
const image = nameImages[imageName] const image = nameImages[imageName]
const img = document.createElement('img') const imgElem = document.createElement('img')
img.classList.add('obf-image', 'ffz--pointer-events', 'ffz-tooltip') imgElem.classList.add('obf-image', 'ffz--pointer-events', 'ffz-tooltip')
img.setAttribute('data-tooltip-type', 'html') imgElem.setAttribute('data-tooltip-type', 'html')
img.setAttribute('data-title', username) imgElem.setAttribute('data-title', username)
img.setAttribute('alt', username) imgElem.setAttribute('alt', username)
img.setAttribute('src', image) imgElem.setAttribute('src', image)
const prefix = document.createElement('span') const prefixElem = document.createElement('span')
prefix.textContent = prefixStr prefixElem.textContent = prefix
const suffix = document.createElement('span') const suffixElem = document.createElement('span')
suffix.textContent = usernameImageTemplateSuffix(newChatMessage) suffixElem.textContent = suffix
textbox.replaceChildren(prefix, img, suffix) container.replaceChildren(prefixElem, imgElem, suffixElem)
} else { } else {
// text name only // text name only
textbox.textContent = `${prefixStr}${username}` container.textContent = `${prefix}${username}`
} }
if (colorbox) { if (doColor) {
colorbox.style.color = newChatMessage.color container.style.color = newChatMessage.color
}
usernamebox.replaceChildren(container)
}
export function eachMutation(record: MutationRecord) {
const target = record.target as HTMLElement
if (target.classList.contains('chat-scrollable-area__message-container')) {
for (const target of record.addedNodes) {
eachMutationTarget(record, target as HTMLElement)
}
} else {
eachMutationTarget(record, record.target as HTMLElement)
}
}
function eachMutationTarget(record: MutationRecord, target: HTMLElement) {
const chatboxMessage = elementTreeFind<HTMLElement, HTMLElement>(
target,
elem =>
elem.parentElement?.classList.contains(
'chat-scrollable-area__message-container'
) || false
)
if (chatboxMessage) {
console.warn('[OBFUSCATOR] mutated message', chatboxMessage, record)
loadChatMessage(chatboxMessage)
loadAdditionalUserNames(chatboxMessage)
} }
} }
+14 -27
View File
@@ -1,37 +1,17 @@
import { loadAdditionalUserNames, loadChatMessage } from './dom' import { eachMutation } from './dom'
const OBSERVER_RATE_LIMIT = 1
let observerLastRun: number = 0
function observerCallback() {
if (Date.now() - observerLastRun < OBSERVER_RATE_LIMIT) {
return
}
observerLastRun = Date.now()
const chatbox = document.querySelector<HTMLDivElement>(
'.chat-scrollable-area__message-container'
)
const chatboxMessages = Array.from(chatbox?.children ?? [])
for (const chatboxMessage of chatboxMessages) {
// set flag on message
if (chatboxMessage.classList.contains('obf-loaded')) {
continue
}
loadChatMessage(chatboxMessage)
loadAdditionalUserNames(chatboxMessage)
}
}
// attach observer // attach observer
const observer = new MutationObserver(observerCallback) const observer = new MutationObserver((mutationRecords: MutationRecord[]) => {
for (const record of mutationRecords) {
eachMutation(record)
}
})
observer.observe(document, { attributes: true, childList: true, subtree: true }) observer.observe(document, { attributes: true, childList: true, subtree: true })
// attach styles // attach styles
const styleAddition = document.createElement('style') const styleAddition = document.createElement('style')
styleAddition.innerHTML = ` styleAddition.innerHTML = `
/* hide badges, except broadcaster and moderator */
.chat-line__message--badges { .chat-line__message--badges {
display: none; display: none;
} }
@@ -46,10 +26,17 @@ styleAddition.innerHTML = `
display: inline-block; display: inline-block;
} }
/* disable 7tv paint colors */
.seventv-paint { .seventv-paint {
background-image: none !important; background-image: none !important;
} }
/* disable username translations */
.chat-author__intl-login {
display: none;
}
/* style image when used as name */
img.obf-image { img.obf-image {
vertical-align: middle; vertical-align: middle;
margin: -0.5rem 0; margin: -0.5rem 0;
+2 -1
View File
@@ -5,5 +5,6 @@
"namespace": "zomo.dev", "namespace": "zomo.dev",
"match": ["https://www.twitch.tv/*"], "match": ["https://www.twitch.tv/*"],
"version": "0.1", "version": "0.1",
"runat": "document-end" "runat": "document-end",
"grant": ["unsafeWindow"]
} }
@@ -9,6 +9,8 @@ export function obfuscator(
return null return null
} }
console.log(`[OBFUSCATOR] Updating Username: ${chatMessage.username}`)
chatMessage.username = chatMessage.username.toLowerCase() chatMessage.username = chatMessage.username.toLowerCase()
// return stored data // return stored data
+5
View File
@@ -14,6 +14,8 @@ export interface NameConfigInstance {
nameCount: number nameCount: number
} }
export type UsernameExtraSuffix = (nameConfig: NameConfigInstance) => string
export const ignoreMod: boolean = false export const ignoreMod: boolean = false
export const nameImages = { export const nameImages = {
@@ -40,3 +42,6 @@ export const nameList: NameConfig[] = [
// image: 'personimage1', // image: 'personimage1',
// }, // },
] ]
export const usernameExtraSuffix: UsernameExtraSuffix = nameConfig =>
nameConfig.nameCount > 0 ? `${nameConfig.nameCount + 1}` : ''
+12 -2
View File
@@ -1,4 +1,4 @@
import { NameConfigInstance, NameConfig, nameList, colorList } from './options' import { NameConfigInstance, nameList, colorList } from './options'
type StoredUsers = { type StoredUsers = {
[username: string]: NameConfigInstance [username: string]: NameConfigInstance
@@ -72,7 +72,17 @@ function loadStoredUserData(): StoredData {
} }
// TODO will be useful for better options // TODO will be useful for better options
export function clearStoredUsers() {} export function clearStoredUsers() {
localStorage.removeItem('obf-data')
storedUsers = {}
nameListUsed = {}
nameListCount = 0
}
;(unsafeWindow as any).obfClear = () => {
clearStoredUsers()
location.reload()
}
export function getRandomName(): NameConfigInstance { export function getRandomName(): NameConfigInstance {
const startingIndex = Math.round(Math.random() * (nameList.length - 1)) const startingIndex = Math.round(Math.random() * (nameList.length - 1))
+21 -2
View File
@@ -1,6 +1,5 @@
# obfuscator todo list # obfuscator todo list
- can i detect when ffz loads?
- better options - better options
## known issues ## known issues
@@ -44,5 +43,25 @@ watch streaks
</div> </div>
</div> </div>
</div> </div>
```
raid message
```html
<div class="Layout-sc-1xcs6mc-0">
<div class="Layout-sc-1xcs6mc-0">
<div class="Layout-sc-1xcs6mc-0 ikqKEy">
<div style="background: rgb(100, 65, 165);" class="Layout-sc-1xcs6mc-0 ijxYla"></div>
<div style="overflow-wrap: break-word;" data-test-selector="user-notice-line"
class="Layout-sc-1xcs6mc-0 cglxbn">
<div class="Layout-sc-1xcs6mc-0 fHdBNk">
<div class="Layout-sc-1xcs6mc-0 hgZmyJ">
<div class="Layout-sc-1xcs6mc-0 jfyitl"><strong>thezomo</strong> is raiding with a party of
<strong>12</strong>.</div>
</div>
</div>
</div>
</div>
</div>
</div>
``` ```
+21 -19
View File
@@ -1,31 +1,33 @@
import { NameConfigInstance } from './options'
export interface ChatMessage { export interface ChatMessage {
username: string username: string
isMod: boolean isMod: boolean
} }
export function innermostElement<T extends Element>(elem: T) { export function innermostElement<T extends Element, U extends Element>(
elem: T
): U {
if (elem.children.length === 0) { if (elem.children.length === 0) {
return elem // U is the type of the innermost element
// since we're at the innermost element, we know T = U
// so we can cast elem (T) to U
return elem as any as U
} }
return innermostElement(elem.children[0]) let child = elem.children[0]
return innermostElement<Element, U>(child)
} }
export function usernameTemplateSuffix(newChatMessage: NameConfigInstance) { export function elementTreeFind<T extends Element, U extends Element>(
if (newChatMessage.nameCount === 0) { elem: T,
return '' fn: (elem: Element) => boolean
): U | null {
if (fn(elem)) {
// U is the type of the element that satisfies fn()
// since we're at the element that satisfies fn(), we know T = U
// so we can cast elem (T) to U
return elem as any as U
} }
if (!elem.parentElement) {
return `${newChatMessage.nameCount}` return null
}
export function usernameImageTemplateSuffix(
newChatMessage: NameConfigInstance
) {
if (newChatMessage.nameCount === 0) {
return ''
} }
return elementTreeFind<Element, U>(elem.parentElement, fn)
return `${newChatMessage.nameCount}`
} }