// ==UserScript== // @name 贴吧楼主层主标识 // @namespace http://tampermonkey.net/ // @version 2.3.3.3 // @description 显示楼中楼的楼主和层主标识 // @icon https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/editor/images/client/image_emoticon1.png // @author necrodancer // @match https://tieba.baidu.com/p/* // @grant none // ==/UserScript== (function() { 'use strict'; // 等待页面加载完成 function waitForPageLoad() { return new Promise(resolve => { if (document.readyState === 'complete') { resolve(); } else { window.addEventListener('load', resolve); } }); } // 获取楼主信息(百度账号名+显示昵称双重匹配) function getLouzhuInfo() { // 1. 先从楼主标识元素获取基础信息 const louzhuElement = document.querySelector('.louzhubiaoshi.j_louzhubiaoshi'); if (!louzhuElement) return null; // 百度账号名(user_name):优先从data-field解析,备选author属性 let userName = louzhuElement.getAttribute('author'); // 显示昵称(showname):从楼主的用户名元素提取 let showname = ''; try { // 2. 从楼主楼层的data-field解析完整信息 const postElement = louzhuElement.closest('div.l_post.j_l_post'); if (postElement) { const dataField = postElement.getAttribute('data-field'); if (dataField) { const postData = JSON.parse(dataField); // 修正:优先使用data-field中的user_name(百度账号名) userName = postData.author?.user_name || userName; // 修正:显示昵称优先从用户名元素的文本提取(最准确) const nameElement = postElement.querySelector('.p_author_name.j_user_card'); showname = nameElement?.textContent?.trim() || ''; } } } catch (e) { console.error('解析楼主信息失败:', e); } return { userName, showname }; } // 获取所有楼层的层主信息(百度账号名+显示昵称) function getCengzhuMap() { const cengzhuMap = new Map(); const postElements = document.querySelectorAll('div.l_post.j_l_post'); postElements.forEach(post => { try { const dataField = post.getAttribute('data-field'); if (!dataField) return; const postData = JSON.parse(dataField); const postId = postData.content.post_id; if (!postId) return; // 层主百度账号名 const userName = postData.author?.user_name; // 层主显示昵称(从用户名元素提取) const nameElement = post.querySelector('.p_author_name.j_user_card'); const showname = nameElement?.textContent?.trim() || ''; if (userName || showname) { cengzhuMap.set(postId, { userName, showname }); } } catch (e) { console.error('解析楼层信息失败:', e); } }); return cengzhuMap; } // 创建标识元素 function createMarkElement(text, className) { const mark = document.createElement('span'); mark.className = `identity-mark ${className}`; mark.style.cssText = ` margin-left: 3px; margin-right: 3px; padding: 2px 3px; font-size: 10px; border-radius: 2px; font-weight: 500; z-index: 10; border: 1px solid currentColor; `; mark.textContent = text; return mark; } // 多维度匹配(百度账号名或显示昵称任一匹配即可) function isMatch(targetInfo, sourceElement) { if (!targetInfo || !sourceElement) return false; // 从被回复者元素中提取两个维度的名称 let sourceUserName = ''; let sourceShowname = sourceElement.textContent.trim(); // 解析被回复者的data-field获取百度账号名 const dataField = sourceElement.getAttribute('data-field'); if (dataField) { try { const cleanedData = dataField.replace(/'/g, '"'); const data = JSON.parse(cleanedData); sourceUserName = data.un || ''; } catch (e) { // 解析失败不影响,继续用显示昵称匹配 } } // 核心:任一维度匹配即判定为同一用户 return (targetInfo.userName && sourceUserName === targetInfo.userName) || (targetInfo.showname && sourceShowname === targetInfo.showname); } // 为楼中楼回复添加标识(重点修复楼主匹配) function addMarks(louzhuInfo, cengzhuMap) { // 匹配所有被@的用户和回复者 const userLinks = document.querySelectorAll('a.at, a.at.j_user_card'); userLinks.forEach(link => { // 避免重复添加 if (link.nextElementSibling && link.nextElementSibling.classList.contains('identity-mark')) { return; } // 获取当前链接所属的楼中楼容器,确定对应的主楼层ID const lzlContainer = link.closest('div.j_lzl_container'); if (!lzlContainer) return; let postId; try { const containerData = lzlContainer.getAttribute('data-field'); if (containerData) { const data = JSON.parse(containerData.replace(/'/g, '"')); postId = data.pid; } } catch (e) { console.error('解析楼中楼容器失败:', e); return; } if (!postId) return; // 获取该主楼层的层主信息 const cengzhuInfo = cengzhuMap.get(postId); const marks = []; // 1. 层主标识(多维度匹配) if (cengzhuInfo && isMatch(cengzhuInfo, link)) { const cengzhuMark = createMarkElement('层主', 'cengzhu-mark'); cengzhuMark.style.color = '#2d64b3'; marks.push(cengzhuMark); } // 2. 楼主标识(重点修复:多维度匹配) if (louzhuInfo && isMatch(louzhuInfo, link)) { const louzhuMark = createMarkElement('楼主', 'louzhu-mark'); louzhuMark.style.color = 'blue'; marks.push(louzhuMark); } if (marks.length > 1) { marks[0].style.marginLeft = '0px'; } // 添加标识到用户名右侧 marks.forEach(mark => { link.parentNode.insertBefore(mark, link.nextSibling); }); }); } // 初始化函数 async function init() { await waitForPageLoad(); const louzhuInfo = getLouzhuInfo(); if (!louzhuInfo) { console.log('未找到楼主信息,仅显示层主标识'); } else { console.log('楼主信息:', louzhuInfo); // 调试用,可删除 } // 初始加载层主信息并添加标识 let cengzhuMap = getCengzhuMap(); addMarks(louzhuInfo, cengzhuMap); // 监听页面动态加载(滚动加载/展开折叠) const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.addedNodes.length > 0) { cengzhuMap = getCengzhuMap(); addMarks(louzhuInfo, cengzhuMap); } }); }); observer.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false }); } // 启动脚本 init(); })();