// ==UserScript== // @name 终极后台自动阅读脚本 // @namespace http://tampermonkey.net/ // @version 3.5.1 // @description 使用最激进的方法强制后台运行,支持真人操作模拟 // @author You // @match https://linux.do/* // @grant none // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/550921/%E7%BB%88%E6%9E%81%E5%90%8E%E5%8F%B0%E8%87%AA%E5%8A%A8%E9%98%85%E8%AF%BB%E8%84%9A%E6%9C%AC.user.js // @updateURL https://update.greasyfork.icu/scripts/550921/%E7%BB%88%E6%9E%81%E5%90%8E%E5%8F%B0%E8%87%AA%E5%8A%A8%E9%98%85%E8%AF%BB%E8%84%9A%E6%9C%AC.meta.js // ==/UserScript== (function() { 'use strict'; let isRunning = false; let scrollCount = 0; let visitedPosts = new Map(); // 改为Map存储时间戳 let mainInterval = null; let scrollInterval = null; let lastScrollTime = 0; let lastStatusUpdate = 0; let lastKeepAlive = 0; let lastBackgroundCheck = 0; let lastBackTime = 0; // 新增:最后一次返回操作时间 // 新增:启动时间记录 let startTime = null; let totalRunTime = 0; // 累计运行时间(毫秒) let sessionStartTime = null; // 当前会话开始时间 // 新增:活动状态管理 let currentActivity = { action: '待机中', icon: '⏸️', timestamp: Date.now(), details: '' }; // 更新当前活动状态 function updateActivity(action, icon = '🔄', details = '') { currentActivity = { action: action, icon: icon, timestamp: Date.now(), details: details }; // 立即更新UI显示 const activityEl = document.getElementById('current-activity'); const activityIconEl = document.getElementById('activity-icon'); const activityTextEl = document.getElementById('activity-text'); if (activityEl && activityIconEl && activityTextEl) { activityIconEl.textContent = icon; activityTextEl.textContent = action; if (details) { activityTextEl.title = details; // 鼠标悬停显示详情 } } } // 新增:增强的去重机制 function isRecentlyVisited(href) { const lastVisit = visitedPosts.get(href); if (!lastVisit) return false; // 1小时内不重复访问 return (Date.now() - lastVisit) < 3600000; } // 添加访问记录 function addVisitedPost(href) { visitedPosts.set(href, Date.now()); // 清理超过24小时的记录,避免内存泄漏 const oneDayAgo = Date.now() - 86400000; for (const [url, timestamp] of visitedPosts.entries()) { if (timestamp < oneDayAgo) { visitedPosts.delete(url); } } } // 获取动态进入频率 function getDynamicEnterFrequency() { const availableLinks = getPostLinks().length; if (availableLinks > 15) return 2; // 很多链接时,每2次滚动尝试 if (availableLinks > 8) return 3; // 中等链接时,每3次滚动尝试 if (availableLinks > 3) return 5; // 较少链接时,每5次滚动尝试 if (availableLinks > 0) return 8; // 很少链接时,每8次滚动尝试 return 15; // 几乎没有链接时,大幅降低频率 } let humanSimulation = { baseScrollInterval: 800, baseScrollDistance: 150, randomFactor: 0.3, // 随机因子,30%的变化范围 pauseChance: 0.05, // 5%的概率暂停 pauseDuration: [1000, 3000], // 暂停1-3秒 nextPauseTime: 0, isInPause: false }; // 新增:状态持久化管理 const STATE_KEYS = { RUNNING: 'ultimate-reader-running', SETTINGS: 'ultimate-reader-settings', STATS: 'ultimate-reader-stats' }; // 保存运行状态 function saveRunningState(running) { try { localStorage.setItem(STATE_KEYS.RUNNING, JSON.stringify({ isRunning: running, timestamp: Date.now() })); } catch (e) { console.log('保存运行状态失败:', e); } } // 获取运行状态 function getRunningState() { try { const data = localStorage.getItem(STATE_KEYS.RUNNING); if (data) { const state = JSON.parse(data); // 如果状态超过1小时,认为已过期 if (Date.now() - state.timestamp < 3600000) { return state.isRunning; } } } catch (e) { console.log('读取运行状态失败:', e); } return false; } // 保存用户设置 function saveSettings() { try { const settings = { scrollInterval: humanSimulation.baseScrollInterval, scrollDistance: humanSimulation.baseScrollDistance, timestamp: Date.now() }; localStorage.setItem(STATE_KEYS.SETTINGS, JSON.stringify(settings)); } catch (e) { console.log('保存设置失败:', e); } } // 加载用户设置 function loadSettings() { try { const data = localStorage.getItem(STATE_KEYS.SETTINGS); if (data) { const settings = JSON.parse(data); humanSimulation.baseScrollInterval = settings.scrollInterval || 800; humanSimulation.baseScrollDistance = settings.scrollDistance || 150; return settings; } } catch (e) { console.log('读取设置失败:', e); } return null; } // 保存统计数据 function saveStats() { try { const stats = { totalRunTime: totalRunTime, startTime: startTime, visitedPostsCount: visitedPosts.size, scrollCount: scrollCount, timestamp: Date.now() }; localStorage.setItem(STATE_KEYS.STATS, JSON.stringify(stats)); } catch (e) { console.log('保存统计数据失败:', e); } } // 加载统计数据 function loadStats() { try { const data = localStorage.getItem(STATE_KEYS.STATS); if (data) { const stats = JSON.parse(data); totalRunTime = stats.totalRunTime || 0; startTime = stats.startTime || null; scrollCount = stats.scrollCount || 0; // 注意:visitedPosts 不恢复,每次重新开始 return stats; } } catch (e) { console.log('读取统计数据失败:', e); } return null; } // 真人操作模拟:生成随机间隔 function getRandomInterval(baseInterval) { const factor = humanSimulation.randomFactor; const min = baseInterval * (1 - factor); const max = baseInterval * (1 + factor); return Math.floor(Math.random() * (max - min + 1)) + min; } // 真人操作模拟:生成随机滚动距离 function getRandomScrollDistance(baseDistance) { const factor = humanSimulation.randomFactor; const min = baseDistance * (1 - factor); const max = baseDistance * (1 + factor); return Math.floor(Math.random() * (max - min + 1)) + min; } // 真人操作模拟:检查是否需要暂停 function shouldPause() { const now = Date.now(); if (now >= humanSimulation.nextPauseTime && Math.random() < humanSimulation.pauseChance) { const pauseDuration = Math.floor(Math.random() * (humanSimulation.pauseDuration[1] - humanSimulation.pauseDuration[0] + 1)) + humanSimulation.pauseDuration[0]; humanSimulation.isInPause = true; humanSimulation.nextPauseTime = now + pauseDuration + Math.random() * 10000 + 5000; // 下次暂停至少5-15秒后 console.log(`😴 模拟真人暂停 ${pauseDuration}ms`); setTimeout(() => { humanSimulation.isInPause = false; console.log('😊 继续操作'); }, pauseDuration); return true; } return false; } // 终极保活方法 function ultimateKeepAlive() { // 1. 重写所有页面可见性API const originalHidden = Object.getOwnPropertyDescriptor(Document.prototype, 'hidden') || Object.getOwnPropertyDescriptor(document, 'hidden'); Object.defineProperty(document, 'hidden', { get: () => false, configurable: true, enumerable: true }); Object.defineProperty(document, 'visibilityState', { get: () => 'visible', configurable: true, enumerable: true }); // 2. 阻止所有可能暂停的事件 const events = ['visibilitychange', 'blur', 'focus', 'pagehide', 'pageshow', 'beforeunload', 'unload']; events.forEach(event => { window.addEventListener(event, (e) => { e.stopImmediatePropagation(); e.preventDefault(); }, { capture: true, passive: false }); document.addEventListener(event, (e) => { e.stopImmediatePropagation(); e.preventDefault(); }, { capture: true, passive: false }); }); // 3. 创建持续的音频上下文 try { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); gainNode.gain.setValueAtTime(0.001, audioContext.currentTime); // 极小音量 oscillator.frequency.setValueAtTime(20000, audioContext.currentTime); oscillator.start(); console.log('🔊 音频上下文已创建'); } catch (e) { console.log('音频创建失败:', e); } // 4. 创建WebRTC连接保持活跃 try { const pc = new RTCPeerConnection(); const dc = pc.createDataChannel('keepalive'); pc.createOffer().then(offer => pc.setLocalDescription(offer)); console.log('📡 WebRTC连接已创建'); } catch (e) { console.log('WebRTC创建失败:', e); } // 5. 预创建事件对象,避免重复创建 const keepAliveEvents = [ new MouseEvent('mousemove', { view: window, bubbles: true, cancelable: true, clientX: 5, clientY: 5 }), new MouseEvent('click', { view: window, bubbles: true, cancelable: true, clientX: 1, clientY: 1 }) ]; // 主定时器 - 合并所有功能 mainInterval = setInterval(() => { const now = Date.now(); // 保活功能 - 每3秒执行一次 if (now - lastKeepAlive >= 3000) { lastKeepAlive = now; // 网络请求保活 fetch('/srv/status', { method: 'HEAD' }).catch(() => {}); // 分发预创建的事件 keepAliveEvents.forEach(event => { document.dispatchEvent(event); }); // 只在页面隐藏时输出日志 if (document.hidden) { console.log('⚠️ 页面隐藏,强制保持活跃'); Object.defineProperty(document, 'hidden', { get: () => false, configurable: true, enumerable: true }); } } // 后台检测 - 每5秒执行一次 if (now - lastBackgroundCheck >= 5000) { lastBackgroundCheck = now; const timeSinceLastScroll = now - lastScrollTime; // 如果超过10秒没有滚动,重新启动 if (isRunning && timeSinceLastScroll > 10000) { console.log('⚠️ 滚动停止,重新启动'); // 清理旧的定时器 if (scrollInterval) { clearTimeout(scrollInterval); scrollInterval = null; } // 重新启动滚动调度 function scheduleNextScroll() { if (!isRunning) return; const randomInterval = getRandomInterval(humanSimulation.baseScrollInterval); scrollInterval = setTimeout(() => { if (!isRunning) return; doScroll(); scheduleNextScroll(); }, randomInterval); } scheduleNextScroll(); } } // 状态更新 - 每3秒执行一次 if (now - lastStatusUpdate >= 3000) { lastStatusUpdate = now; updateStatus(); } }, 1000); // 主定时器每1秒检查一次 console.log('🔒 终极保活系统已启动'); } // 获取帖子链接 - 优化版本,缓存结果 + 智能选择 let cachedLinks = null; let lastCacheTime = 0; const CACHE_DURATION = 5000; // 延长缓存到5秒 // 优化的选择器 - 针对linux.do const OPTIMIZED_SELECTORS = [ '.topic-list-item .main-link a.title', // 主要帖子标题 '.topic-list tbody tr .main-link a.title', // 表格形式主链接 '.topic-list tbody tr td a.title', // 表格形式标题 '.topic-list tr td a[href*="/t/"]', // 表格中的帖子链接 '[data-topic-id] .title a', // 带topic-id的链接 'table tr td a[href*="/t/"]', // 通用表格帖子链接 'a[href*="/t/"]' // 兜底选择器 ]; function getPostLinks() { const now = Date.now(); // 使用缓存结果 if (cachedLinks && (now - lastCacheTime) < CACHE_DURATION) { return cachedLinks; } let links = []; for (const selector of OPTIMIZED_SELECTORS) { links = document.querySelectorAll(selector); if (links.length > 0) break; } const filteredLinks = Array.from(links).filter(link => { return link.href && link.href.includes('/t/') && !isRecentlyVisited(link.href) && link.textContent.trim().length > 5; }); // 缓存结果 cachedLinks = filteredLinks; lastCacheTime = now; return filteredLinks; } // 智能帖子选择算法 function calculatePostScore(link) { let score = 0; try { // 1. 回复数权重 (从相邻元素获取) const replyElement = link.closest('tr')?.querySelector('.posts, .num.posts, [title*="replies"], [title*="回复"]'); if (replyElement) { const replyCount = parseInt(replyElement.textContent.trim()) || 0; score += Math.min(replyCount * 2, 20); // 最多20分 } // 2. 标题长度权重 (适中长度更好) const titleLength = link.textContent.trim().length; if (titleLength >= 10 && titleLength <= 50) { score += 15; // 理想长度 } else if (titleLength > 5) { score += Math.min(titleLength / 5, 10); // 其他长度 } // 3. 活跃度权重 (从最后回复时间) const timeElement = link.closest('tr')?.querySelector('.relative-date, .age, time'); if (timeElement) { const timeText = timeElement.textContent.trim(); if (timeText.includes('分钟') || timeText.includes('小时') || timeText.includes('min') || timeText.includes('hour')) { score += 10; // 最近活跃 } else if (timeText.includes('天') || timeText.includes('day')) { score += 5; // 近期活跃 } } // 4. 避免过长标题 (可能是垃圾内容) if (titleLength > 100) { score -= 5; } // 5. 特殊标记加分 const titleText = link.textContent.trim().toLowerCase(); if (titleText.includes('教程') || titleText.includes('分享') || titleText.includes('tutorial') || titleText.includes('guide')) { score += 8; // 教程类内容 } } catch (e) { // 如果获取信息失败,给予基础分数 score = 5; } return Math.max(score, 1); // 最低1分 } // 智能选择最佳帖子 function selectBestPost(links) { if (links.length === 0) return null; if (links.length === 1) return links[0]; // 计算每个帖子的分数 const scoredLinks = links.map(link => ({ element: link, score: calculatePostScore(link) })); // 按分数排序 scoredLinks.sort((a, b) => b.score - a.score); // 从前30%中随机选择,保持一定随机性 const topCount = Math.max(1, Math.ceil(scoredLinks.length * 0.3)); const topLinks = scoredLinks.slice(0, topCount); const selected = topLinks[Math.floor(Math.random() * topLinks.length)]; console.log(`🎯 智能选择: 分数${selected.score}, 标题: ${selected.element.textContent.trim().substring(0, 30)}...`); return selected.element; } // 进入帖子 - 智能选择版本 function enterPost() { const links = getPostLinks(); if (links.length === 0) { updateActivity('等待新内容', '⏳', '暂无可访问的帖子链接'); return false; } updateActivity('分析帖子质量', '🧠', `正在从${links.length}个帖子中智能选择`); const selectedLink = selectBestPost(links); if (!selectedLink) { updateActivity('选择失败', '❌', '未能找到合适的帖子'); return false; } const title = selectedLink.textContent.trim().substring(0, 30); updateActivity('进入优质帖子', '📖', `正在进入:${title}...`); console.log(`🎯 智能进入: ${title}...`); addVisitedPost(selectedLink.href); selectedLink.click(); return true; } // 检测页面类型 function getPageType() { return window.location.href.includes('/t/') && window.location.href.match(/\/\d+$/) ? 'post' : 'list'; } // 执行滚动 - 智能加速版本 + 真人操作模拟 function doScroll() { if (!isRunning) return; // 检查是否需要暂停(真人操作模拟) if (humanSimulation.isInPause) { updateActivity('暂停思考中', '😴', '模拟真人暂停,增强真实感'); return; // 暂停中,跳过本次滚动 } if (shouldPause()) { return; // 开始暂停,跳过本次滚动 } // 更新最后滚动时间 lastScrollTime = Date.now(); scrollCount++; const pageType = getPageType(); // 更新活动状态 updateActivity('智能滚动中', '📜', `第${scrollCount}次滚动,页面类型:${pageType}`); // 只在每10次滚动时输出日志,减少日志频率 if (scrollCount % 10 === 0) { const time = new Date().toLocaleTimeString(); console.log(`🔄 [${time}] 滚动#${scrollCount} [${pageType}]`); } const scrollTop = window.pageYOffset; const windowHeight = window.innerHeight; const documentHeight = document.documentElement.scrollHeight; // 智能滚动距离:列表页面更快,帖子页面适中 let scrollDistance = humanSimulation.baseScrollDistance; // 使用基础距离 // 获取用户设置的滚动距离 const distanceSlider = document.getElementById('distance-slider'); if (distanceSlider) { scrollDistance = parseInt(distanceSlider.value); humanSimulation.baseScrollDistance = scrollDistance; // 更新基础距离 } if (pageType === 'list') { scrollDistance = Math.min(scrollDistance * 1.3, 300); // 列表页面更快,但不超过300px } else if (pageType === 'post') { scrollDistance = Math.min(scrollDistance * 0.7, 200); // 帖子页面适中,但不超过200px } // 应用真人操作模拟:随机滚动距离 scrollDistance = getRandomScrollDistance(scrollDistance); // 智能底部检测 - 提前触发避免浪费滚动 const distanceToBottom = documentHeight - (scrollTop + windowHeight); const isNearBottom = distanceToBottom <= 200; // 提前200px检测 if (isNearBottom) { console.log(`📍 接近页面底部 (距离: ${distanceToBottom}px)`); if (pageType === 'list') { updateActivity('寻找优质帖子', '🔍', '页面底部,准备进入帖子'); if (enterPost()) { scrollCount = 0; return; } } else { // 添加返回操作的冷却时间检查 const now = Date.now(); const timeSinceLastBack = now - lastBackTime; if (timeSinceLastBack < 3000) { // 3秒冷却时间 updateActivity('等待返回冷却', '⏳', `距离上次返回${Math.ceil((3000 - timeSinceLastBack) / 1000)}秒`); return; // 跳过本次返回操作 } updateActivity('返回帖子列表', '🔙', '帖子阅读完成,返回列表'); console.log('📖 返回列表'); lastBackTime = now; // 记录返回操作时间 // 尝试多种返回方法 try { // 方法1: 使用history.back() window.history.back(); // 方法2: 如果3秒后仍在同一页面,尝试直接跳转 setTimeout(() => { const currentPageType = getPageType(); if (currentPageType === 'post') { console.log('🔄 返回失败,尝试直接跳转到主页'); updateActivity('强制返回主页', '🏠', '常规返回失败,直接跳转'); // 尝试跳转到主页或分类页面 const currentUrl = window.location.href; const baseUrl = currentUrl.split('/t/')[0]; window.location.href = baseUrl + '/latest'; } }, 3000); } catch (e) { console.log('返回操作失败:', e); updateActivity('返回失败', '❌', '返回操作出现错误'); } scrollCount = 0; return; } } // 尝试进入帖子 - 列表页面使用动态频率 if (pageType === 'list') { const enterFrequency = getDynamicEnterFrequency(); const tryEnterInterval = scrollCount % enterFrequency === 0; if (tryEnterInterval) { updateActivity('智能选择帖子', '🎯', `每${enterFrequency}次滚动尝试进入帖子`); if (enterPost()) { scrollCount = 0; return; } } } // 执行智能滚动(带随机性) window.scrollBy(0, scrollDistance); } // 动态调整滚动间隔 function getScrollInterval() { const pageType = getPageType(); if (pageType === 'list') { return 600; // 列表页面更快 } else if (pageType === 'post') { return 1000; // 帖子页面适中 } return 800; // 默认 } // 启动自动阅读 - 规范化版本 function startReading() { if (isRunning) return; isRunning = true; // 记录启动时间 sessionStartTime = Date.now(); if (!startTime) { startTime = sessionStartTime; // 首次启动时间 } // 重置真人操作模拟状态 humanSimulation.nextPauseTime = Date.now() + Math.random() * 10000 + 5000; // 5-15秒后可能暂停 humanSimulation.isInPause = false; // 更新活动状态 updateActivity('系统启动中', '🚀', '正在初始化智能阅读系统'); // 保存运行状态 saveRunningState(true); // 启动保活系统 ultimateKeepAlive(); // 启动滚动定时器 - 使用简单的单一定时器 function scheduleNextScroll() { if (!isRunning) return; const randomInterval = getRandomInterval(humanSimulation.baseScrollInterval); scrollInterval = setTimeout(() => { if (!isRunning) return; doScroll(); scheduleNextScroll(); // 递归调度下一次滚动 }, randomInterval); } scheduleNextScroll(); // 立即更新按钮状态 updateStatus(); // 启动后更新活动状态 setTimeout(() => { updateActivity('准备就绪', '✅', '智能阅读系统已启动,开始工作'); }, 1000); console.log('🚀 终极后台自动阅读已启动'); console.log('⚡ 使用真人操作模拟模式'); console.log('🔒 终极保活系统运行中'); console.log(`⏰ 启动时间: ${new Date(sessionStartTime).toLocaleTimeString()}`); } // 停止自动阅读 - 规范化版本 function stopReading() { if (!isRunning) return; isRunning = false; // 更新活动状态 updateActivity('系统停止中', '⏹️', '正在安全停止所有操作'); // 记录运行时间 if (sessionStartTime) { const sessionDuration = Date.now() - sessionStartTime; totalRunTime += sessionDuration; console.log(`⏱️ 本次运行时长: ${formatDuration(sessionDuration)}`); console.log(`📊 累计运行时长: ${formatDuration(totalRunTime)}`); } // 保存运行状态和统计数据 saveRunningState(false); saveStats(); // 清理所有定时器 if (scrollInterval) { clearTimeout(scrollInterval); // 改为clearTimeout scrollInterval = null; } if (mainInterval) { clearInterval(mainInterval); mainInterval = null; } // 重置状态 sessionStartTime = null; humanSimulation.isInPause = false; lastBackTime = 0; // 重置返回操作时间 // 立即更新按钮状态 updateStatus(); // 停止后更新活动状态 updateActivity('待机中', '⏸️', '系统已停止,等待下次启动'); console.log('⏹️ 自动阅读已停止'); } // 格式化时长显示 function formatDuration(ms) { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (hours > 0) { return `${hours}小时${minutes % 60}分钟${seconds % 60}秒`; } else if (minutes > 0) { return `${minutes}分钟${seconds % 60}秒`; } else { return `${seconds}秒`; } } // 创建现代化控制面板 function createPanel() { const panel = document.createElement('div'); panel.id = 'ultimate-reader-panel'; panel.style.cssText = ` position: fixed; top: 20px; right: 20px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(20px); border-radius: 16px; padding: 20px; z-index: 99999; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #2d3748; box-shadow: 0 20px 40px rgba(0,0,0,0.1), 0 0 0 1px rgba(255,255,255,0.2); min-width: 280px; max-width: 320px; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border: 1px solid rgba(255,255,255,0.3); `; panel.innerHTML = `
⚡ 智能阅读器
滚动速度
800ms
滚动距离
150px
0
滚动次数
0
访问帖子
00:00
本次运行
00:00
累计时间
页面: 未知
已停止
⏸️ 待机中
`; document.body.appendChild(panel); // 事件绑定 document.getElementById('ultimate-start').addEventListener('click', startReading); document.getElementById('ultimate-stop').addEventListener('click', stopReading); // 速度调节功能 - 修复版本 const speedSlider = document.getElementById('speed-slider'); const speedValue = document.getElementById('speed-value'); speedSlider.addEventListener('input', (e) => { const value = parseInt(e.target.value); speedValue.textContent = value + 'ms'; // 直接更新基础间隔值 humanSimulation.baseScrollInterval = value; // 保存设置 saveSettings(); console.log(`⚡ 滚动速度已调整为: ${value}ms`); }); // 距离调节功能 const distanceSlider = document.getElementById('distance-slider'); const distanceValue = document.getElementById('distance-value'); distanceSlider.addEventListener('input', (e) => { const value = parseInt(e.target.value); distanceValue.textContent = value + 'px'; // 更新基础距离 humanSimulation.baseScrollDistance = value; // 保存设置 saveSettings(); }); // 测试功能 document.getElementById('test-links').addEventListener('click', () => { const links = getPostLinks(); console.log(`🔍 找到 ${links.length} 个帖子链接`); // 显示通知 showNotification(`找到 ${links.length} 个帖子链接`, 'info'); }); document.getElementById('test-enter').addEventListener('click', () => { if (enterPost()) { showNotification('成功进入帖子', 'success'); } else { showNotification('没有找到可进入的帖子', 'warning'); } }); document.getElementById('clear-visited').addEventListener('click', () => { visitedPosts.clear(); cachedLinks = null; // 清除缓存 updateStatus(); // 立即更新状态显示 showNotification('已清空访问记录', 'success'); }); // 状态更新函数 - 增强版本 function updateStatus() { const scrollCountEl = document.getElementById('scroll-count'); const visitedCountEl = document.getElementById('visited-count'); const pageTypeEl = document.getElementById('page-type'); const statusEl = document.getElementById('status'); const sessionTimeEl = document.getElementById('session-time'); const totalTimeEl = document.getElementById('total-time'); const startTimeInfoEl = document.getElementById('start-time-info'); const startTimeDisplayEl = document.getElementById('start-time-display'); // 新增:按钮状态控制 const startBtn = document.getElementById('ultimate-start'); const stopBtn = document.getElementById('ultimate-stop'); if (scrollCountEl) scrollCountEl.textContent = scrollCount; if (visitedCountEl) visitedCountEl.textContent = visitedPosts.size; if (pageTypeEl) pageTypeEl.textContent = getPageType(); if (statusEl) { statusEl.textContent = isRunning ? '运行中' : '已停止'; statusEl.style.color = isRunning ? '#10b981' : '#e53e3e'; } // 按钮互斥状态控制 if (startBtn && stopBtn) { if (isRunning) { startBtn.disabled = true; stopBtn.disabled = false; } else { startBtn.disabled = false; stopBtn.disabled = true; } } // 更新运行时间显示 if (sessionTimeEl) { if (isRunning && sessionStartTime) { const sessionDuration = Date.now() - sessionStartTime; sessionTimeEl.textContent = formatDurationShort(sessionDuration); } else { sessionTimeEl.textContent = '00:00'; } } if (totalTimeEl) { let displayTotalTime = totalRunTime; if (isRunning && sessionStartTime) { displayTotalTime += (Date.now() - sessionStartTime); } totalTimeEl.textContent = formatDurationShort(displayTotalTime); } // 显示/隐藏启动时间信息 if (startTimeInfoEl && startTimeDisplayEl) { if (isRunning && sessionStartTime) { startTimeInfoEl.style.display = 'block'; startTimeDisplayEl.textContent = new Date(sessionStartTime).toLocaleTimeString(); } else { startTimeInfoEl.style.display = 'none'; } } } // 格式化时长显示(简短版本) function formatDurationShort(ms) { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (hours > 0) { return `${hours}:${String(minutes % 60).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`; } else { return `${String(minutes).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`; } } // 通知功能 function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: ${type === 'success' ? '#10b981' : type === 'warning' ? '#f59e0b' : '#3b82f6'}; color: white; padding: 12px 20px; border-radius: 8px; font-size: 14px; font-weight: 500; z-index: 100000; box-shadow: 0 10px 25px rgba(0,0,0,0.2); animation: slideDown 0.3s ease; `; notification.textContent = message; // 添加动画样式 const style = document.createElement('style'); style.textContent = ` @keyframes slideDown { from { opacity: 0; transform: translateX(-50%) translateY(-20px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } `; document.head.appendChild(style); document.body.appendChild(notification); setTimeout(() => { notification.remove(); style.remove(); }, 3000); } // 导出函数供外部使用 window.updateStatus = updateStatus; window.showNotification = showNotification; // 初始化按钮状态 updateStatus(); // 应用保存的设置到UI applySettingsToUI(); } // 初始化 - 增强版本 function init() { console.log('⚡ 终极后台自动阅读脚本已加载'); console.log('💡 使用最激进的方法确保后台运行'); // 加载保存的数据 loadSettings(); loadStats(); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { createPanel(); // 延迟检查自动启动,确保页面完全加载 setTimeout(checkAutoStart, 1000); }); } else { createPanel(); // 延迟检查自动启动,确保页面完全加载 setTimeout(checkAutoStart, 1000); } } // 检查并自动启动 function checkAutoStart() { const shouldAutoStart = getRunningState(); if (shouldAutoStart) { console.log('🔄 检测到之前的运行状态,自动启动...'); updateActivity('自动恢复中', '🔄', '检测到之前的运行状态,正在自动启动'); startReading(); } else { updateActivity('待机中', '⏸️', '系统已就绪,等待用户启动'); } } // 应用保存的设置到UI function applySettingsToUI() { const speedSlider = document.getElementById('speed-slider'); const speedValue = document.getElementById('speed-value'); const distanceSlider = document.getElementById('distance-slider'); const distanceValue = document.getElementById('distance-value'); if (speedSlider && speedValue) { speedSlider.value = humanSimulation.baseScrollInterval; speedValue.textContent = humanSimulation.baseScrollInterval + 'ms'; } if (distanceSlider && distanceValue) { distanceSlider.value = humanSimulation.baseScrollDistance; distanceValue.textContent = humanSimulation.baseScrollDistance + 'px'; } } init(); })();