百度贴吧点赞数据显示

在百度贴吧显示主题帖、楼层的点赞数据

  1. // ==UserScript==
  2. // @name 百度贴吧点赞数据显示
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description 在百度贴吧显示主题帖、楼层的点赞数据
  6. // @author noahacgn
  7. // @match *://tieba.baidu.com/p/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @grant GM_registerMenuCommand
  12. // @connect tiebac.baidu.com
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // 配置信息
  20. const config = {
  21. BDUSS: '', // 用户手动填写BDUSS
  22. CLIENT_INFO: {
  23. _client_version: "12.64.1.1",
  24. _client_type: "2"
  25. },
  26. BASE_URL: "http://tiebac.baidu.com",
  27. lastUrl: location.href, // 记录上一次处理的URL
  28. postDataCache: {}, // 缓存帖子数据
  29. isProcessing: false // 是否正在处理数据
  30. };
  31.  
  32. // 初始化
  33. function init() {
  34. console.log("百度贴吧点赞数据显示脚本初始化...");
  35. // 从GM存储中获取BDUSS
  36. config.BDUSS = GM_getValue('BDUSS', '');
  37. // 如果没有BDUSS,则提示用户设置
  38. if (!config.BDUSS) {
  39. showBDUSSPrompt();
  40. } else {
  41. // 获取当前帖子ID
  42. const tid = getTidFromUrl();
  43. if (tid) {
  44. console.log("获取到帖子ID:", tid);
  45. // 获取帖子点赞数据
  46. getPostData(tid);
  47. } else {
  48. console.error("无法从URL获取帖子ID");
  49. }
  50. }
  51. }
  52.  
  53. // 显示BDUSS设置提示
  54. function showBDUSSPrompt() {
  55. const userBDUSS = prompt("请输入您的BDUSS值以获取点赞数据:", "");
  56. if (userBDUSS) {
  57. config.BDUSS = userBDUSS;
  58. GM_setValue('BDUSS', userBDUSS);
  59. // 获取当前帖子ID
  60. const tid = getTidFromUrl();
  61. if (tid) {
  62. // 获取帖子点赞数据
  63. getPostData(tid);
  64. }
  65. }
  66. }
  67.  
  68. // 从URL获取帖子ID
  69. function getTidFromUrl() {
  70. const match = window.location.href.match(/p\/(\d+)/);
  71. return match ? match[1] : null;
  72. }
  73.  
  74. // 获取当前页码
  75. function getCurrentPage() {
  76. const match = window.location.href.match(/pn=(\d+)/);
  77. return match ? parseInt(match[1]) : 1;
  78. }
  79.  
  80. // 加密签名函数
  81. function generateSign(params) {
  82. // 先排序参数
  83. const sortedParams = new URLSearchParams(params);
  84. sortedParams.sort();
  85. // 构建签名字符串
  86. const signStr = Array.from(sortedParams.entries())
  87. .map(entry => entry.join('='))
  88. .join('') + "tiebaclient!!!";
  89. // 计算MD5
  90. return md5(signStr).toUpperCase();
  91. }
  92.  
  93. // 打包请求参数,添加签名
  94. function packRequest(params) {
  95. const reqParams = { ...params, ...config.CLIENT_INFO };
  96. // 添加BDUSS
  97. if (!reqParams.BDUSS) {
  98. reqParams.BDUSS = config.BDUSS;
  99. }
  100. // 生成签名
  101. const sign = generateSign(reqParams);
  102. reqParams.sign = sign;
  103. return new URLSearchParams(reqParams).toString();
  104. }
  105.  
  106. // 使用GM_xmlhttpRequest调用百度贴吧API
  107. function fetchAPI(url, data, method = "GET") {
  108. return new Promise((resolve, reject) => {
  109. let apiUrl = config.BASE_URL + url;
  110. const fetchOptions = {
  111. method: method,
  112. headers: {
  113. "Content-Type": "application/x-www-form-urlencoded",
  114. },
  115. onload: function(response) {
  116. if (response.status >= 200 && response.status < 300) {
  117. try {
  118. const responseData = JSON.parse(response.responseText);
  119. resolve(responseData);
  120. } catch (error) {
  121. reject(new Error("API返回数据解析失败: " + error.message));
  122. }
  123. } else {
  124. reject(new Error(`HTTP错误! 状态: ${response.status}`));
  125. }
  126. },
  127. onerror: function(error) {
  128. reject(new Error("API请求失败: " + error.message));
  129. }
  130. };
  131.  
  132. // 根据方法添加不同的参数
  133. if (method === "GET") {
  134. if (data) {
  135. apiUrl += `?${data}`;
  136. }
  137. } else if (method === "POST") {
  138. fetchOptions.data = data;
  139. }
  140.  
  141. GM_xmlhttpRequest({
  142. ...fetchOptions,
  143. url: apiUrl
  144. });
  145. });
  146. }
  147.  
  148. // 获取帖子数据(包含点赞信息)
  149. async function getPostData(tid) {
  150. try {
  151. if (config.isProcessing) {
  152. console.log("正在处理数据,稍后再试");
  153. return;
  154. }
  155.  
  156. config.isProcessing = true;
  157. const currentPage = getCurrentPage();
  158. console.log(`开始获取帖子数据,帖子ID: ${tid},页码: ${currentPage}`);
  159. // 构造请求参数
  160. const params = {
  161. kz: tid,
  162. pn: currentPage,
  163. rn: 30, // 每页回复数量
  164. r: 3, // 排序方式: 3为时间正序
  165. BDUSS: config.BDUSS
  166. };
  167. // 发起请求
  168. const data = await fetchAPI("/c/f/pb/page", packRequest(params), "POST");
  169. console.log("获取到帖子数据:", data);
  170. if (!data || data.error) {
  171. throw new Error(`获取帖子数据失败: ${data?.error_msg || '未知错误'}`);
  172. }
  173. // 缓存帖子数据
  174. const cacheKey = `${tid}_${currentPage}`;
  175. config.postDataCache[cacheKey] = data;
  176. // 使用智能延迟处理显示
  177. setTimeout(() => {
  178. processPostData(tid, currentPage);
  179. }, 500);
  180. return data;
  181. } catch (error) {
  182. console.error("获取帖子点赞数据失败:", error);
  183. config.isProcessing = false;
  184. return null;
  185. }
  186. }
  187.  
  188. // 处理帖子数据并显示点赞信息
  189. function processPostData(tid, page) {
  190. const cacheKey = `${tid}_${page}`;
  191. const data = config.postDataCache[cacheKey];
  192. if (!data) {
  193. console.error("缓存中找不到帖子数据:", cacheKey);
  194. config.isProcessing = false;
  195. return;
  196. }
  197. try {
  198. // 只在第一页显示主题帖点赞数据
  199. if (page === 1 && data.thread) {
  200. displayThreadLikeCount(data.thread);
  201. }
  202. // 检查页面是否已经加载完成
  203. const postsLoaded = checkPostsLoaded(data);
  204. if (postsLoaded) {
  205. console.log("页面已加载完成,显示点赞数据");
  206. // 显示回复的点赞数据
  207. if (data.post_list && Array.isArray(data.post_list) && data.post_list.length > 0) {
  208. data.post_list.forEach(post => {
  209. if (!post) return;
  210. displayPostLikeCount(post);
  211. });
  212. }
  213. // 处理完成
  214. config.isProcessing = false;
  215. } else {
  216. console.log("页面尚未加载完成,500ms后重试");
  217. // 如果页面未加载完,延迟重试
  218. setTimeout(() => {
  219. processPostData(tid, page);
  220. }, 500);
  221. }
  222. } catch (error) {
  223. console.error("处理帖子数据出错:", error);
  224. config.isProcessing = false;
  225. }
  226. }
  227.  
  228. // 检查页面是否加载完成
  229. function checkPostsLoaded(data) {
  230. if (!data.post_list || !Array.isArray(data.post_list) || data.post_list.length === 0) {
  231. return true; // 没有回复,认为加载完成
  232. }
  233. // 检查页面是否已加载数据中的第一个和最后一个帖子
  234. const firstPost = data.post_list[0];
  235. const lastPost = data.post_list[data.post_list.length - 1];
  236. if (!firstPost || !lastPost || !firstPost.id || !lastPost.id) {
  237. return false;
  238. }
  239. const firstPostElement = document.querySelector(`.l_post[data-pid="${firstPost.id}"]`);
  240. const lastPostElement = document.querySelector(`.l_post[data-pid="${lastPost.id}"]`);
  241. return firstPostElement && lastPostElement;
  242. }
  243.  
  244. // 显示主题帖点赞数
  245. function displayThreadLikeCount(thread) {
  246. const titleElement = document.querySelector('.core_title_txt.pull-left.text-overflow');
  247. if (titleElement) {
  248. const likeCount = thread.agree?.agree_num || 0;
  249. // 检查是否已经添加了点赞计数
  250. const existingLikeElement = document.querySelector('.thread-like-count');
  251. if (existingLikeElement) {
  252. return;
  253. }
  254. const likeElement = document.createElement('span');
  255. likeElement.className = 'thread-like-count';
  256. likeElement.innerHTML = `<span style="color: #E74C3C; margin-left: 10px;"><i style="font-size: 14px; margin-right: 3px;">❤</i>${likeCount}</span>`;
  257. titleElement.after(likeElement);
  258. console.log("已显示主题帖点赞数:", likeCount);
  259. }
  260. }
  261.  
  262. // 显示楼层点赞数
  263. function displayPostLikeCount(post) {
  264. if (!post || !post.id) {
  265. console.warn("无效的回复数据:", post);
  266. return;
  267. }
  268. const postElement = document.querySelector(`.l_post[data-pid="${post.id}"]`);
  269. if (postElement) {
  270. const tailElement = postElement.querySelector('.core_reply_tail');
  271. if (tailElement) {
  272. // 检查是否已经添加了点赞计数
  273. const existingLikeElement = tailElement.querySelector('.post-like-count');
  274. if (existingLikeElement) {
  275. return;
  276. }
  277. const likeCount = post.agree?.agree_num || 0;
  278. const likeElement = document.createElement('span');
  279. likeElement.className = 'post-like-count';
  280. likeElement.innerHTML = `<span class="tail-info" style="color: #E74C3C;"><i style="font-size: 12px; margin-right: 3px;">❤</i>${likeCount}</span>`;
  281. const timeElement = tailElement.querySelector('.tail-info:last-of-type');
  282. if (timeElement) {
  283. timeElement.after(likeElement);
  284. } else {
  285. const postTailWrap = tailElement.querySelector('.post-tail-wrap');
  286. if (postTailWrap) {
  287. postTailWrap.appendChild(likeElement);
  288. }
  289. }
  290. console.log("已显示楼层点赞数,回复ID:", post.id, "点赞数:", likeCount);
  291. }
  292. } else {
  293. console.warn("未找到对应的楼层元素,回复ID:", post.id);
  294. }
  295. }
  296.  
  297. // 检查URL变化
  298. function checkUrlChange() {
  299. if (config.lastUrl !== location.href) {
  300. console.log("URL已变化,从", config.lastUrl, "变为", location.href);
  301. config.lastUrl = location.href;
  302. // 清除处理中状态
  303. config.isProcessing = false;
  304. // 获取当前帖子ID
  305. const tid = getTidFromUrl();
  306. if (tid) {
  307. console.log("URL变化后重新获取点赞数据,帖子ID:", tid);
  308. // 给页面一些时间加载
  309. setTimeout(() => {
  310. // 获取帖子点赞数据
  311. getPostData(tid);
  312. }, 1000);
  313. }
  314. }
  315. }
  316.  
  317. // MD5算法实现
  318. function md5(string) {
  319. function RotateLeft(lValue, iShiftBits) {
  320. return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
  321. }
  322. function AddUnsigned(lX, lY) {
  323. var lX4, lY4, lX8, lY8, lResult;
  324. lX8 = (lX & 0x80000000);
  325. lY8 = (lY & 0x80000000);
  326. lX4 = (lX & 0x40000000);
  327. lY4 = (lY & 0x40000000);
  328. lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
  329. if (lX4 & lY4) {
  330. return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
  331. }
  332. if (lX4 | lY4) {
  333. if (lResult & 0x40000000) {
  334. return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
  335. } else {
  336. return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
  337. }
  338. } else {
  339. return (lResult ^ lX8 ^ lY8);
  340. }
  341. }
  342. function F(x, y, z) { return (x & y) | ((~x) & z); }
  343. function G(x, y, z) { return (x & z) | (y & (~z)); }
  344. function H(x, y, z) { return (x ^ y ^ z); }
  345. function I(x, y, z) { return (y ^ (x | (~z))); }
  346. function FF(a, b, c, d, x, s, ac) {
  347. a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
  348. return AddUnsigned(RotateLeft(a, s), b);
  349. }
  350. function GG(a, b, c, d, x, s, ac) {
  351. a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
  352. return AddUnsigned(RotateLeft(a, s), b);
  353. }
  354. function HH(a, b, c, d, x, s, ac) {
  355. a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
  356. return AddUnsigned(RotateLeft(a, s), b);
  357. }
  358. function II(a, b, c, d, x, s, ac) {
  359. a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
  360. return AddUnsigned(RotateLeft(a, s), b);
  361. }
  362. function ConvertToWordArray(string) {
  363. var lWordCount;
  364. var lMessageLength = string.length;
  365. var lNumberOfWords_temp1 = lMessageLength + 8;
  366. var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
  367. var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
  368. var lWordArray = Array(lNumberOfWords - 1);
  369. var lBytePosition = 0;
  370. var lByteCount = 0;
  371. while (lByteCount < lMessageLength) {
  372. lWordCount = (lByteCount - (lByteCount % 4)) / 4;
  373. lBytePosition = (lByteCount % 4) * 8;
  374. lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
  375. lByteCount++;
  376. }
  377. lWordCount = (lByteCount - (lByteCount % 4)) / 4;
  378. lBytePosition = (lByteCount % 4) * 8;
  379. lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
  380. lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
  381. lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
  382. return lWordArray;
  383. }
  384. function WordToHex(lValue) {
  385. var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
  386. for (lCount = 0; lCount <= 3; lCount++) {
  387. lByte = (lValue >>> (lCount * 8)) & 255;
  388. WordToHexValue_temp = "0" + lByte.toString(16);
  389. WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
  390. }
  391. return WordToHexValue;
  392. }
  393. function Utf8Encode(string) {
  394. string = string.replace(/\r\n/g, "\n");
  395. var utftext = "";
  396. for (var n = 0; n < string.length; n++) {
  397. var c = string.charCodeAt(n);
  398. if (c < 128) {
  399. utftext += String.fromCharCode(c);
  400. }
  401. else if ((c > 127) && (c < 2048)) {
  402. utftext += String.fromCharCode((c >> 6) | 192);
  403. utftext += String.fromCharCode((c & 63) | 128);
  404. }
  405. else {
  406. utftext += String.fromCharCode((c >> 12) | 224);
  407. utftext += String.fromCharCode(((c >> 6) & 63) | 128);
  408. utftext += String.fromCharCode((c & 63) | 128);
  409. }
  410. }
  411. return utftext;
  412. }
  413. var x = Array();
  414. var k, AA, BB, CC, DD, a, b, c, d;
  415. var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
  416. var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
  417. var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
  418. var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
  419. string = Utf8Encode(string);
  420. x = ConvertToWordArray(string);
  421. a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
  422. for (k = 0; k < x.length; k += 16) {
  423. AA = a; BB = b; CC = c; DD = d;
  424. a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
  425. d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
  426. c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
  427. b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
  428. a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
  429. d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
  430. c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
  431. b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
  432. a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
  433. d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
  434. c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
  435. b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
  436. a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
  437. d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
  438. c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
  439. b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
  440. a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
  441. d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
  442. c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
  443. b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
  444. a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
  445. d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
  446. c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
  447. b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
  448. a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
  449. d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
  450. c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
  451. b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
  452. a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
  453. d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
  454. c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
  455. b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
  456. a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
  457. d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
  458. c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
  459. b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
  460. a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
  461. d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
  462. c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
  463. b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
  464. a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
  465. d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
  466. c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
  467. b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
  468. a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
  469. d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
  470. c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
  471. b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
  472. a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
  473. d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
  474. c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
  475. b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
  476. a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
  477. d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
  478. c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
  479. b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
  480. a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
  481. d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
  482. c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
  483. b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
  484. a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
  485. d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
  486. c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
  487. b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
  488. a = AddUnsigned(a, AA);
  489. b = AddUnsigned(b, BB);
  490. c = AddUnsigned(c, CC);
  491. d = AddUnsigned(d, DD);
  492. }
  493. var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
  494. return temp.toLowerCase();
  495. }
  496.  
  497. // 添加样式
  498. function addCustomStyles() {
  499. const style = document.createElement('style');
  500. style.textContent = `
  501. .thread-like-count, .post-like-count {
  502. display: inline-block;
  503. animation: fadeIn 0.5s;
  504. }
  505. @keyframes fadeIn {
  506. from { opacity: 0; }
  507. to { opacity: 1; }
  508. }
  509. `;
  510. document.head.appendChild(style);
  511. }
  512.  
  513. // 注册(不可用)油猴菜单
  514. GM_registerMenuCommand("设置BDUSS", () => {
  515. const currentBDUSS = GM_getValue('BDUSS', '');
  516. const userBDUSS = prompt("请输入您的BDUSS值以获取点赞数据:", currentBDUSS || "");
  517. if (userBDUSS) {
  518. config.BDUSS = userBDUSS;
  519. GM_setValue('BDUSS', userBDUSS);
  520. // 刷新点赞数据
  521. const tid = getTidFromUrl();
  522. if (tid) getPostData(tid);
  523. }
  524. });
  525.  
  526. // 初始化函数
  527. function runScript() {
  528. addCustomStyles();
  529. init();
  530. // 由于贴吧页面有时会动态加载内容,需要监听DOM变化
  531. const observer = new MutationObserver(function(mutations) {
  532. mutations.forEach(function(mutation) {
  533. if (mutation.addedNodes && mutation.addedNodes.length > 0) {
  534. // 如果有新的楼层添加,尝试显示点赞数据
  535. for (let i = 0; i < mutation.addedNodes.length; i++) {
  536. const node = mutation.addedNodes[i];
  537. if (node.nodeType === 1 && node.classList.contains('l_post')) {
  538. const tid = getTidFromUrl();
  539. const currentPage = getCurrentPage();
  540. const cacheKey = `${tid}_${currentPage}`;
  541. // 如果有缓存数据,尝试直接使用缓存的数据为新加载的楼层添加点赞数
  542. if (config.postDataCache[cacheKey] && !config.isProcessing) {
  543. const cachedData = config.postDataCache[cacheKey];
  544. const postId = node.getAttribute('data-pid');
  545. if (postId && cachedData.post_list) {
  546. const post = cachedData.post_list.find(p => p && p.id === postId);
  547. if (post) {
  548. displayPostLikeCount(post);
  549. }
  550. }
  551. } else if (tid && !config.isProcessing) {
  552. // 如果没有缓存数据或正在处理,则重新获取
  553. getPostData(tid);
  554. }
  555. break;
  556. }
  557. }
  558. }
  559. });
  560. });
  561. observer.observe(document.body, { childList: true, subtree: true });
  562. // 监听URL变化(针对翻页)
  563. // 方法1:使用事件监听(适用于单页应用)
  564. window.addEventListener('popstate', () => {
  565. checkUrlChange();
  566. });
  567. // 方法2:周期性检查URL(适用于任何情况)
  568. setInterval(checkUrlChange, 1000);
  569. // 方法3:监听贴吧的翻页事件(适用于贴吧特定实现)
  570. document.addEventListener('click', (e) => {
  571. // 检查是否点击了翻页链接
  572. if (e.target && (e.target.classList.contains('pagination-item') ||
  573. e.target.closest('.pagination-item'))) {
  574. // 给点击翻页一些时间来改变URL和加载内容
  575. setTimeout(checkUrlChange, 500);
  576. }
  577. });
  578. }
  579.  
  580. // 确保脚本在页面加载后运行
  581. if (document.readyState === "loading") {
  582. window.addEventListener('DOMContentLoaded', runScript);
  583. } else {
  584. runScript();
  585. }
  586. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址