add all files

This commit is contained in:
Julian Freeman
2025-07-01 20:16:57 -04:00
parent 26b71500ef
commit 4581297dac
11 changed files with 617 additions and 2 deletions

428
content.js Normal file
View File

@@ -0,0 +1,428 @@
const PERSON_ID_PREFIX = 'chat-topic-person-';
const ICON_ID_PREFIX = "presence-pill-";
const CHAT_ROSTER_PREFIX = "chat-roster-item-name-";
const SUGGEST_PEOPLE_PREFIX = "AUTOSUGGEST_SUGGESTION_PEOPLE";
const ROSTER_AVATAR_PREFIX = "roster-avatar-img-";
const SERP_PEOPLE_CARD_PREFIX = "serp-people-card-content-";
const PEOPLE_PICKER_PREFIX = "people-picker-entry-";
const PEOPLE_PICKER_SEL_PREFIX = "people-picker-selected-user-";
let debounceTimer = null;
let isMutating = false;
async function saveAlias(id, alias) {
const key = id.replace(PERSON_ID_PREFIX, "");
const result = await chrome.storage.local.get('aliases');
const aliases = result.aliases || {};
// 新的别名为空就删除
if (alias) {
aliases[key] = alias;
} else {
delete aliases[key];
}
await chrome.storage.local.set({ aliases });
}
async function getAlias(id) {
const key = id.replace(PERSON_ID_PREFIX, "");
const result = await chrome.storage.local.get('aliases');
const aliases = result.aliases || {};
return aliases[key] || null;
}
// 设置别名显示 + 按钮添加
function applyAliasAndButton(el) {
const id = el.id;
if (!id || !id.startsWith(PERSON_ID_PREFIX)) return;
const existingBtn = document.querySelector(`[data-floating-btn-for="${id}"]`);
if (!existingBtn) {
const rect = el.getBoundingClientRect();
const button = document.createElement('button');
button.textContent = '设置别名';
button.style.position = 'fixed';
button.style.left = `${rect.left + window.scrollX}px`;
button.style.top = `${rect.bottom + window.scrollY + 20}px`;
button.style.zIndex = '99999';
button.style.padding = '4px 8px';
button.style.fontSize = '12px';
button.style.backgroundColor = '#0078d4';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '4px';
button.style.cursor = 'pointer';
button.setAttribute('data-floating-btn-for', id);
button.addEventListener('click', async () => {
const current = (await getAlias(id.replace(PERSON_ID_PREFIX, ""))) || document.getElementById(id)?.textContent || '';
const newAlias = prompt("请输入别名:", current);
// 如果是空字符串还是得进入
if (newAlias !== null) {
const el = document.getElementById(id); // 🔥 重新获取最新的元素
if (el && newAlias) el.textContent = newAlias.trim();
await saveAlias(id.replace(PERSON_ID_PREFIX, ""), newAlias.trim());
}
if (newAlias === "") {
alert("别名已删除");
}
});
document.body.appendChild(button);
}
// 应用别名(异步)
getAlias(id.replace(PERSON_ID_PREFIX, "")).then(alias => {
if (alias && el.textContent !== alias) {
el.textContent = alias;
}
});
}
// 主要查找右侧消息列表中的名字并修改
function applyRightChatAlias(el) {
let id = el.id;
if (!id || !id.startsWith(ICON_ID_PREFIX)) return;
let parent = el;
// 向上查找 4 个父元素
for (let i = 0; i < 4; i++) {
if (parent.parentElement) {
parent = parent.parentElement;
} else {
return; // 如果不足4层就跳过
}
}
// 获取前一个兄弟元素
const prevSibling = parent.previousElementSibling;
if (!prevSibling) return;
// 向下查找第 4 个子元素(层级式)
let target = prevSibling;
for (let i = 0; i < 4; i++) {
if (target.children.length > 0) {
target = target.children[0]; // 每层往下取第一个子元素
} else {
return; // 不足4层跳过
}
}
// 判断符合才修改
if (target.getAttribute('data-tid') === 'message-author-name') {
getAlias(id.replace(ICON_ID_PREFIX, "")).then(alias => {
if (alias && target.textContent !== alias) {
target.textContent = alias;
}
});
}
}
// 主要查找左侧消息列表中的名字并修改
function applyLeftChatAlias(el) {
let id = el.id;
if (!id || !id.startsWith(ICON_ID_PREFIX)) return;
let parent = el;
// 向上查找 3 个父元素
for (let i = 0; i < 3; i++) {
if (parent.parentElement) {
parent = parent.parentElement;
} else {
return; // 如果不足3层就跳过
}
}
// 获取后一个兄弟元素
const nextSibling = parent.nextElementSibling;
if (!nextSibling) return;
// 向下查找第 2 个子元素(层级式)
let target = nextSibling;
for (let i = 0; i < 2; i++) {
if (target.children.length > 0) {
target = target.children[0]; // 每层往下取第一个子元素
} else {
return; // 不足2层跳过
}
}
// 判断符合才修改
if (target.getAttribute('data-tid') === 'chat-list-item-title') {
getAlias(id.replace(ICON_ID_PREFIX, "")).then(alias => {
if (alias && target.textContent !== alias) {
target.textContent = alias;
}
});
}
}
// 修改群组人员的名称
function applyChatRosterAlias(el) {
let id = el.id;
if (!id || !id.startsWith(CHAT_ROSTER_PREFIX)) return;
getAlias(id.replace(CHAT_ROSTER_PREFIX, "")).then(alias => {
if (alias && el.textContent !== alias) {
el.textContent = alias;
}
});
}
// 群组添加人员的别名
function applyPeoplePickerAlias(el) {
let tid = el.getAttribute('data-tid');
if (!tid || !tid.startsWith(PEOPLE_PICKER_PREFIX)) return;
let child = el.children[1];
// 向下查找第 3 个子元素(层级式)
for (let i = 0; i < 3; i++) {
if (child.children.length > 0) {
child = child.children[0]; // 每层往下取第一个子元素
} else {
return; // 不足3层跳过
}
}
if (child.tagName.toLowerCase() === 'span') {
let id = "8:" + tid.replace(PEOPLE_PICKER_PREFIX, "");
getAlias(id).then(alias => {
if (alias && child.textContent !== alias) {
child.textContent = alias;
}
});
}
}
// 群组添加人员时选中的人员
function applyPeoplePickerSelectedAlias(el) {
let tid = el.getAttribute('data-tid');
if (!tid || !tid.startsWith(PEOPLE_PICKER_SEL_PREFIX)) return;
let id = "8:" + tid.replace(PEOPLE_PICKER_SEL_PREFIX, "");
getAlias(id).then(alias => {
if (alias && el.textContent !== alias) {
el.textContent = alias;
}
});
}
// 追加搜索框中的人员别名
function applySuggestPeopleAlias(el) {
let tid = el.getAttribute('data-tid');
if (!tid || !tid.startsWith(SUGGEST_PEOPLE_PREFIX)) return;
let child = el.children[1]; // 第二个子元素
// 向下查找第 2 个子元素(层级式)
for (let i = 0; i < 2; i++) {
if (child.children.length > 0) {
child = child.children[0]; // 每层往下取第一个子元素
} else {
return; // 不足2层跳过
}
}
if (child.getAttribute('data-tid') !== 'AUTOSUGGEST_SUGGESTION_TITLE') return;
let id = tid.replace(SUGGEST_PEOPLE_PREFIX, "");
getAlias(id).then(alias => {
if (alias) {
let lastSpan = child.lastElementChild;
if (lastSpan.id.startsWith("suggest-alias-attached")) {
if (lastSpan.textContent === `[${alias}]`) return;
lastSpan.textContent = `[${alias}]`;
} else {
const span = document.createElement('span');
span.id = `suggest-alias-attached-${id}`;
span.textContent = `[${alias}]`;
span.style.marginLeft = '4px';
span.style.color = document.documentElement.classList.contains("theme-tfl-default") ? '#ed0833' : '#78ef0b';
child.appendChild(span);
}
}
});
}
// 追加人员搜索中的别名
function applySerpPeopleAlias(el) {
let id = el.id;
if (!id || !id.startsWith(SERP_PEOPLE_CARD_PREFIX)) return;
let child = el.children[2];
// 向下查找第 4 个子元素(层级式)
for (let i = 0; i < 4; i++) {
if (child.children.length > 0) {
child = child.children[0]; // 每层往下取第一个子元素
} else {
return; // 不足4层跳过
}
}
id = id.replace(SERP_PEOPLE_CARD_PREFIX, "");
getAlias(id).then(alias => {
if (alias) {
let lastSpan = child.lastElementChild;
if (lastSpan.id.startsWith("people-card-attached")) {
if (lastSpan.textContent === `[${alias}]`) return;
lastSpan.textContent = `[${alias}]`;
} else {
const span = document.createElement('span');
span.id = `people-card-attached-${id}`;
span.textContent = `[${alias}]`;
span.style.marginLeft = '4px';
span.style.color = document.documentElement.classList.contains("theme-tfl-default") ? '#ed0833' : '#78ef0b';
child.appendChild(span);
}
}
});
}
// 修改通话中的人名
function applyCallingAlias(el) {
if (el.getAttribute('data-cid') !== 'calling-participant-stream') return;
let child = el.children[1];
// 向下查找第 5 个子元素(层级式)
for (let i = 0; i < 5; i++) {
if (child.children.length > 0) {
child = child.children[0]; // 每层往下取第一个子元素
} else {
return; // 不足5层跳过
}
}
if (child.tagName.toLowerCase() === 'span') {
getAlias(el.getAttribute('data-acc-element-id')).then(alias => {
if (alias && child.textContent !== alias) {
child.textContent = alias;
}
});
}
}
// 修改通话右侧人名的别名
function applyRosterAvatarAlias(el) {
let id = el.id;
if (!id || !id.startsWith(ROSTER_AVATAR_PREFIX)) return;
getAlias(id.replace(ROSTER_AVATAR_PREFIX, "")).then(alias => {
if (alias && el.textContent !== alias) {
el.textContent = alias;
}
});
}
// 查看此通话中的人员
function applyPeopleInCall(el) {
let id = el.id;
if (!id || !id.startsWith(ICON_ID_PREFIX)) return;
let parent = el;
// 向上查找 2 个父元素
for (let i = 0; i < 2; i++) {
if (parent.parentElement) {
parent = parent.parentElement;
} else {
return; // 如果不足2层就跳过
}
}
// 一个是查看此通话中的参与者,一个是呼叫其他人加入
if ([
"audio_dropin_add_participants_dialog_renderer",
"audio-drop-in-live-roster"
].includes(parent.getAttribute("data-tid"))) {
let target = parent.nextElementSibling;
if (!target) return;
if (target.tagName.toLowerCase() === "span") {
getAlias(id.replace(ICON_ID_PREFIX, "")).then(alias => {
if (alias && target.textContent !== alias) {
target.textContent = alias;
}
});
}
}
}
// 回应表情的人员别名
function applyReactionAlias(el) {
if (el.getAttribute('data-tid') !== 'diverse-reaction-user-list-item') return;
try {
const tabster = JSON.parse(el.getAttribute("data-tabster"));
let child = el.children[1];
let target = child.children[0];
let id = tabster.observed.names[0];
getAlias(id).then(alias => {
if (alias && target.textContent !== alias) {
target.textContent = alias;
}
});
} catch (error) {}
}
// 查找所有目标元素应用别名和按钮
function applyToAll() {
document.querySelectorAll('[data-floating-btn-for]').forEach(btn => btn.remove());
const allPersons = document.querySelectorAll(`[id^="${PERSON_ID_PREFIX}"]`);
allPersons.forEach(el => applyAliasAndButton(el));
const allIcons = document.querySelectorAll(`[id^="${ICON_ID_PREFIX}"]`);
allIcons.forEach(el => {
applyRightChatAlias(el);
applyLeftChatAlias(el);
applyPeopleInCall(el);
});
const allChatRoster = document.querySelectorAll(`[id^="${CHAT_ROSTER_PREFIX}"]`);
allChatRoster.forEach(el => applyChatRosterAlias(el));
const allSuggestPeople = document.querySelectorAll(`[data-tid^="${SUGGEST_PEOPLE_PREFIX}"]`);
allSuggestPeople.forEach(el => applySuggestPeopleAlias(el));
const allCalling = document.querySelectorAll(`[data-cid="calling-participant-stream"]`);
allCalling.forEach(el => applyCallingAlias(el));
const allRosterAvatar = document.querySelectorAll(`[id^="${ROSTER_AVATAR_PREFIX}"]`);
allRosterAvatar.forEach(el => applyRosterAvatarAlias(el));
const allSerpPeople = document.querySelectorAll(`[id^="${SERP_PEOPLE_CARD_PREFIX}"]`);
allSerpPeople.forEach(el => applySerpPeopleAlias(el));
const allPeoplePicker = document.querySelectorAll(`[data-tid^="${PEOPLE_PICKER_PREFIX}"]`);
allPeoplePicker.forEach(el => applyPeoplePickerAlias(el));
const allPeoplePickerSelected = document.querySelectorAll(`[data-tid^="${PEOPLE_PICKER_SEL_PREFIX}"]`);
allPeoplePickerSelected.forEach(el => applyPeoplePickerSelectedAlias(el));
const allReaction = document.querySelectorAll(`[data-tid="diverse-reaction-user-list-item"]`);
allReaction.forEach(el => applyReactionAlias(el));
}
// 初始化逻辑
function init() {
const observer = new MutationObserver(() => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
if (isMutating) return; // 🧠 防止自己触发自己
isMutating = true;
applyToAll(); // 页面内容变动后重新应用
// 给浏览器一点时间完成 DOM 更新后再允许 observer 响应
setTimeout(() => {
isMutating = false;
}, 500); // 至少比这个高才行,不然会一直触发
}, 300);
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
applyToAll(); // 初始执行
// 兜底:每 2 秒再扫一次(避免漏掉异步更新)
// setInterval(() => {
// applyToAll();
// }, 2000);
}
init();