|
|
发表于 2026-9-8 18:41:47
|
显示全部楼层
- // ==UserScript==
- // @name RitDon 帖子自动刷新新楼层
- // @namespace http://tampermonkey.net/
- // @version 1.0
- // @description 自动检测并加载 RitDon 论坛帖子中的新楼层(AJAX 无刷新)
- // @author You
- // @match https://ritdon.com/forum.php?mod=viewthread&tid=*
- // @grant GM_xmlhttpRequest
- // @grant GM_notification
- // @grant GM_info
- // ==/UserScript==
- (function() {
- 'use strict';
- // ========== 配置 ==========
- const CHECK_INTERVAL = 15000; // 检查间隔(毫秒),15秒
- const ENABLE_NOTIFICATION = true; // 是否显示新楼层通知
- // ========== 状态变量 ==========
- let maxPid = 0; // 当前已加载的最大帖子 PID
- let currentTotalPages = 0; // 当前总页数
- // ========== 工具函数 ==========
- /** 从页面中提取当前已加载的最大 PID */
- function getCurrentMaxPid() {
- const postDivs = document.querySelectorAll('#postlist div[id^="post_"]');
- let max = 0;
- postDivs.forEach(div => {
- const pidStr = div.id.replace('post_', '');
- const pid = parseInt(pidStr, 10);
- if (!isNaN(pid) && pid > max) max = pid;
- });
- return max;
- }
- /** 从页面中提取总页数 */
- function getTotalPages() {
- const label = document.querySelector('#pgt .pg label span');
- if (!label) return 0;
- // 文本格式如 " / 90 页",提取数字
- const match = label.textContent.match(/(\d+)/);
- return match ? parseInt(match[1], 10) : 0;
- }
- /** 构造指定页码的帖子页面 URL */
- function getPageUrl(page) {
- const base = location.pathname + location.search.replace(/&?page=\d+/, '');
- const separator = base.includes('?') ? '&' : '?';
- return base + separator + 'page=' + page;
- }
- /** 从 HTML 中提取所有帖子数据(PID → HTML 片段) */
- function extractPostsFromHtml(html) {
- const parser = new DOMParser();
- const doc = parser.parseFromString(html, 'text/html');
- const postDivs = doc.querySelectorAll('#postlist div[id^="post_"]');
- const result = {};
- postDivs.forEach(div => {
- const pidStr = div.id.replace('post_', '');
- const pid = parseInt(pidStr, 10);
- if (!isNaN(pid)) {
- result[pid] = div.outerHTML;
- }
- });
- return result;
- }
- /** 将新楼层插入到页面底部 */
- function insertNewPosts(newPostsHtml) {
- const postlist = document.getElementById('postlist');
- if (!postlist) return;
- // 按 PID 排序(从小到大),保证插入顺序正确
- const sortedPids = Object.keys(newPostsHtml).map(Number).sort((a, b) => a - b);
- for (const pid of sortedPids) {
- // 检查是否已存在(防止重复插入)
- if (document.getElementById('post_' + pid)) continue;
- postlist.insertAdjacentHTML('beforeend', newPostsHtml[pid]);
- }
- }
- /** 执行一次刷新检查 */
- function checkNewPosts() {
- // 1. 获取当前总页数
- const totalPages = getTotalPages();
- if (totalPages === 0) {
- // 可能页面还没加载完,稍后重试
- return;
- }
- // 2. 如果总页数发生变化,或者首次运行,更新状态并请求最后一页
- if (totalPages !== currentTotalPages || maxPid === 0) {
- currentTotalPages = totalPages;
- }
- // 3. 请求最后一页
- const lastPageUrl = getPageUrl(currentTotalPages);
- GM_xmlhttpRequest({
- method: 'GET',
- url: lastPageUrl,
- onload: function(response) {
- if (response.status !== 200) return;
- const posts = extractPostsFromHtml(response.responseText);
- const newPosts = {};
- let newMaxPid = maxPid;
- // 找出所有比当前最大 PID 大的帖子
- for (const [pid, html] of Object.entries(posts)) {
- const pidNum = parseInt(pid, 10);
- if (pidNum > maxPid) {
- newPosts[pid] = html;
- if (pidNum > newMaxPid) newMaxPid = pidNum;
- }
- }
- // 如果有新帖子,插入并更新状态
- const newCount = Object.keys(newPosts).length;
- if (newCount > 0) {
- insertNewPosts(newPosts);
- maxPid = newMaxPid;
- // 桌面通知
- if (ENABLE_NOTIFICATION && typeof GM_notification !== 'undefined') {
- GM_notification({
- text: `发现 ${newCount} 个新楼层`,
- timeout: 3000
- });
- }
- // 在页面标题上提示(可选)
- if (document.title && !document.title.startsWith('📩')) {
- document.title = '📩 ' + document.title;
- setTimeout(() => {
- document.title = document.title.replace('📩 ', '');
- }, 5000);
- }
- }
- },
- onerror: function() {
- // 静默失败,下次重试
- }
- });
- }
- // ========== 初始化 ==========
- function init() {
- maxPid = getCurrentMaxPid();
- currentTotalPages = getTotalPages();
- // 如果总页数获取失败,延迟重试
- if (currentTotalPages === 0) {
- setTimeout(init, 2000);
- return;
- }
- // 首次检查延迟几秒,避免与页面加载冲突
- setTimeout(checkNewPosts, 3000);
- // 定时检查
- setInterval(checkNewPosts, CHECK_INTERVAL);
- console.log('[自动刷新] 已启动,当前最大PID:', maxPid, '总页数:', currentTotalPages);
- }
- // 等待 DOM 就绪
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', init);
- } else {
- init();
- }
- })();
复制代码
水楼自动刷新 15秒一次 看上去可行 |
|