您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在百度贴吧显示主题帖、楼层的点赞数据
// ==UserScript== // @name 百度贴吧点赞数据显示 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 在百度贴吧显示主题帖、楼层的点赞数据 // @author noahacgn // @match *://tieba.baidu.com/p/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @connect tiebac.baidu.com // @license MIT // ==/UserScript== (function() { 'use strict'; // 配置信息 const config = { BDUSS: '', // 用户手动填写BDUSS CLIENT_INFO: { _client_version: "12.64.1.1", _client_type: "2" }, BASE_URL: "http://tiebac.baidu.com", lastUrl: location.href, // 记录上一次处理的URL postDataCache: {}, // 缓存帖子数据 isProcessing: false // 是否正在处理数据 }; // 初始化 function init() { console.log("百度贴吧点赞数据显示脚本初始化..."); // 从GM存储中获取BDUSS config.BDUSS = GM_getValue('BDUSS', ''); // 如果没有BDUSS,则提示用户设置 if (!config.BDUSS) { showBDUSSPrompt(); } else { // 获取当前帖子ID const tid = getTidFromUrl(); if (tid) { console.log("获取到帖子ID:", tid); // 获取帖子点赞数据 getPostData(tid); } else { console.error("无法从URL获取帖子ID"); } } } // 显示BDUSS设置提示 function showBDUSSPrompt() { const userBDUSS = prompt("请输入您的BDUSS值以获取点赞数据:", ""); if (userBDUSS) { config.BDUSS = userBDUSS; GM_setValue('BDUSS', userBDUSS); // 获取当前帖子ID const tid = getTidFromUrl(); if (tid) { // 获取帖子点赞数据 getPostData(tid); } } } // 从URL获取帖子ID function getTidFromUrl() { const match = window.location.href.match(/p\/(\d+)/); return match ? match[1] : null; } // 获取当前页码 function getCurrentPage() { const match = window.location.href.match(/pn=(\d+)/); return match ? parseInt(match[1]) : 1; } // 加密签名函数 function generateSign(params) { // 先排序参数 const sortedParams = new URLSearchParams(params); sortedParams.sort(); // 构建签名字符串 const signStr = Array.from(sortedParams.entries()) .map(entry => entry.join('=')) .join('') + "tiebaclient!!!"; // 计算MD5 return md5(signStr).toUpperCase(); } // 打包请求参数,添加签名 function packRequest(params) { const reqParams = { ...params, ...config.CLIENT_INFO }; // 添加BDUSS if (!reqParams.BDUSS) { reqParams.BDUSS = config.BDUSS; } // 生成签名 const sign = generateSign(reqParams); reqParams.sign = sign; return new URLSearchParams(reqParams).toString(); } // 使用GM_xmlhttpRequest调用百度贴吧API function fetchAPI(url, data, method = "GET") { return new Promise((resolve, reject) => { let apiUrl = config.BASE_URL + url; const fetchOptions = { method: method, headers: { "Content-Type": "application/x-www-form-urlencoded", }, onload: function(response) { if (response.status >= 200 && response.status < 300) { try { const responseData = JSON.parse(response.responseText); resolve(responseData); } catch (error) { reject(new Error("API返回数据解析失败: " + error.message)); } } else { reject(new Error(`HTTP错误! 状态: ${response.status}`)); } }, onerror: function(error) { reject(new Error("API请求失败: " + error.message)); } }; // 根据方法添加不同的参数 if (method === "GET") { if (data) { apiUrl += `?${data}`; } } else if (method === "POST") { fetchOptions.data = data; } GM_xmlhttpRequest({ ...fetchOptions, url: apiUrl }); }); } // 获取帖子数据(包含点赞信息) async function getPostData(tid) { try { if (config.isProcessing) { console.log("正在处理数据,稍后再试"); return; } config.isProcessing = true; const currentPage = getCurrentPage(); console.log(`开始获取帖子数据,帖子ID: ${tid},页码: ${currentPage}`); // 构造请求参数 const params = { kz: tid, pn: currentPage, rn: 30, // 每页回复数量 r: 3, // 排序方式: 3为时间正序 BDUSS: config.BDUSS }; // 发起请求 const data = await fetchAPI("/c/f/pb/page", packRequest(params), "POST"); console.log("获取到帖子数据:", data); if (!data || data.error) { throw new Error(`获取帖子数据失败: ${data?.error_msg || '未知错误'}`); } // 缓存帖子数据 const cacheKey = `${tid}_${currentPage}`; config.postDataCache[cacheKey] = data; // 使用智能延迟处理显示 setTimeout(() => { processPostData(tid, currentPage); }, 500); return data; } catch (error) { console.error("获取帖子点赞数据失败:", error); config.isProcessing = false; return null; } } // 处理帖子数据并显示点赞信息 function processPostData(tid, page) { const cacheKey = `${tid}_${page}`; const data = config.postDataCache[cacheKey]; if (!data) { console.error("缓存中找不到帖子数据:", cacheKey); config.isProcessing = false; return; } try { // 只在第一页显示主题帖点赞数据 if (page === 1 && data.thread) { displayThreadLikeCount(data.thread); } // 检查页面是否已经加载完成 const postsLoaded = checkPostsLoaded(data); if (postsLoaded) { console.log("页面已加载完成,显示点赞数据"); // 显示回复的点赞数据 if (data.post_list && Array.isArray(data.post_list) && data.post_list.length > 0) { data.post_list.forEach(post => { if (!post) return; displayPostLikeCount(post); }); } // 处理完成 config.isProcessing = false; } else { console.log("页面尚未加载完成,500ms后重试"); // 如果页面未加载完,延迟重试 setTimeout(() => { processPostData(tid, page); }, 500); } } catch (error) { console.error("处理帖子数据出错:", error); config.isProcessing = false; } } // 检查页面是否加载完成 function checkPostsLoaded(data) { if (!data.post_list || !Array.isArray(data.post_list) || data.post_list.length === 0) { return true; // 没有回复,认为加载完成 } // 检查页面是否已加载数据中的第一个和最后一个帖子 const firstPost = data.post_list[0]; const lastPost = data.post_list[data.post_list.length - 1]; if (!firstPost || !lastPost || !firstPost.id || !lastPost.id) { return false; } const firstPostElement = document.querySelector(`.l_post[data-pid="${firstPost.id}"]`); const lastPostElement = document.querySelector(`.l_post[data-pid="${lastPost.id}"]`); return firstPostElement && lastPostElement; } // 显示主题帖点赞数 function displayThreadLikeCount(thread) { const titleElement = document.querySelector('.core_title_txt.pull-left.text-overflow'); if (titleElement) { const likeCount = thread.agree?.agree_num || 0; // 检查是否已经添加了点赞计数 const existingLikeElement = document.querySelector('.thread-like-count'); if (existingLikeElement) { return; } const likeElement = document.createElement('span'); likeElement.className = 'thread-like-count'; likeElement.innerHTML = `<span style="color: #E74C3C; margin-left: 10px;"><i style="font-size: 14px; margin-right: 3px;">❤</i>${likeCount}</span>`; titleElement.after(likeElement); console.log("已显示主题帖点赞数:", likeCount); } } // 显示楼层点赞数 function displayPostLikeCount(post) { if (!post || !post.id) { console.warn("无效的回复数据:", post); return; } const postElement = document.querySelector(`.l_post[data-pid="${post.id}"]`); if (postElement) { const tailElement = postElement.querySelector('.core_reply_tail'); if (tailElement) { // 检查是否已经添加了点赞计数 const existingLikeElement = tailElement.querySelector('.post-like-count'); if (existingLikeElement) { return; } const likeCount = post.agree?.agree_num || 0; const likeElement = document.createElement('span'); likeElement.className = 'post-like-count'; likeElement.innerHTML = `<span class="tail-info" style="color: #E74C3C;"><i style="font-size: 12px; margin-right: 3px;">❤</i>${likeCount}</span>`; const timeElement = tailElement.querySelector('.tail-info:last-of-type'); if (timeElement) { timeElement.after(likeElement); } else { const postTailWrap = tailElement.querySelector('.post-tail-wrap'); if (postTailWrap) { postTailWrap.appendChild(likeElement); } } console.log("已显示楼层点赞数,回复ID:", post.id, "点赞数:", likeCount); } } else { console.warn("未找到对应的楼层元素,回复ID:", post.id); } } // 检查URL变化 function checkUrlChange() { if (config.lastUrl !== location.href) { console.log("URL已变化,从", config.lastUrl, "变为", location.href); config.lastUrl = location.href; // 清除处理中状态 config.isProcessing = false; // 获取当前帖子ID const tid = getTidFromUrl(); if (tid) { console.log("URL变化后重新获取点赞数据,帖子ID:", tid); // 给页面一些时间加载 setTimeout(() => { // 获取帖子点赞数据 getPostData(tid); }, 1000); } } } // MD5算法实现 function md5(string) { function RotateLeft(lValue, iShiftBits) { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); } function AddUnsigned(lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 0x80000000); lY8 = (lY & 0x80000000); lX4 = (lX & 0x40000000); lY4 = (lY & 0x40000000); lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); if (lX4 & lY4) { return (lResult ^ 0x80000000 ^ lX8 ^ lY8); } if (lX4 | lY4) { if (lResult & 0x40000000) { return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); } else { return (lResult ^ 0x40000000 ^ lX8 ^ lY8); } } else { return (lResult ^ lX8 ^ lY8); } } function F(x, y, z) { return (x & y) | ((~x) & z); } function G(x, y, z) { return (x & z) | (y & (~z)); } function H(x, y, z) { return (x ^ y ^ z); } function I(x, y, z) { return (y ^ (x | (~z))); } function FF(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); } function GG(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); } function HH(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); } function II(a, b, c, d, x, s, ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); } function ConvertToWordArray(string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWords_temp1 = lMessageLength + 8; var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64; var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++; } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray; } function WordToHex(lValue) { var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValue_temp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2); } return WordToHexValue; } function Utf8Encode(string) { string = string.replace(/\r\n/g, "\n"); var utftext = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if ((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; } var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = Utf8Encode(string); x = ConvertToWordArray(string); a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB); b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613); b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501); a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8); d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122); d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193); c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E); b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821); a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340); c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); d = GG(d, a, b, c, x[k + 10], S22, 0x2441453); c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681); c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05); a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); a = II(a, b, c, d, x[k + 0], S41, 0xF4292244); d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97); c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039); a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3); d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1); a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); c = II(c, d, a, b, x[k + 6], S43, 0xA3014314); b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82); d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391); a = AddUnsigned(a, AA); b = AddUnsigned(b, BB); c = AddUnsigned(c, CC); d = AddUnsigned(d, DD); } var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d); return temp.toLowerCase(); } // 添加样式 function addCustomStyles() { const style = document.createElement('style'); style.textContent = ` .thread-like-count, .post-like-count { display: inline-block; animation: fadeIn 0.5s; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } `; document.head.appendChild(style); } // 注册油猴菜单 GM_registerMenuCommand("设置BDUSS", () => { const currentBDUSS = GM_getValue('BDUSS', ''); const userBDUSS = prompt("请输入您的BDUSS值以获取点赞数据:", currentBDUSS || ""); if (userBDUSS) { config.BDUSS = userBDUSS; GM_setValue('BDUSS', userBDUSS); // 刷新点赞数据 const tid = getTidFromUrl(); if (tid) getPostData(tid); } }); // 初始化函数 function runScript() { addCustomStyles(); init(); // 由于贴吧页面有时会动态加载内容,需要监听DOM变化 const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes && mutation.addedNodes.length > 0) { // 如果有新的楼层添加,尝试显示点赞数据 for (let i = 0; i < mutation.addedNodes.length; i++) { const node = mutation.addedNodes[i]; if (node.nodeType === 1 && node.classList.contains('l_post')) { const tid = getTidFromUrl(); const currentPage = getCurrentPage(); const cacheKey = `${tid}_${currentPage}`; // 如果有缓存数据,尝试直接使用缓存的数据为新加载的楼层添加点赞数 if (config.postDataCache[cacheKey] && !config.isProcessing) { const cachedData = config.postDataCache[cacheKey]; const postId = node.getAttribute('data-pid'); if (postId && cachedData.post_list) { const post = cachedData.post_list.find(p => p && p.id === postId); if (post) { displayPostLikeCount(post); } } } else if (tid && !config.isProcessing) { // 如果没有缓存数据或正在处理,则重新获取 getPostData(tid); } break; } } } }); }); observer.observe(document.body, { childList: true, subtree: true }); // 监听URL变化(针对翻页) // 方法1:使用事件监听(适用于单页应用) window.addEventListener('popstate', () => { checkUrlChange(); }); // 方法2:周期性检查URL(适用于任何情况) setInterval(checkUrlChange, 1000); // 方法3:监听贴吧的翻页事件(适用于贴吧特定实现) document.addEventListener('click', (e) => { // 检查是否点击了翻页链接 if (e.target && (e.target.classList.contains('pagination-item') || e.target.closest('.pagination-item'))) { // 给点击翻页一些时间来改变URL和加载内容 setTimeout(checkUrlChange, 500); } }); } // 确保脚本在页面加载后运行 if (document.readyState === "loading") { window.addEventListener('DOMContentLoaded', runScript); } else { runScript(); } })();