您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在指定网站上自动保活,定时滚动和刷新页面,用户操作会重置计时
// ==UserScript== // @name 网站保活助手 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 在指定网站上自动保活,定时滚动和刷新页面,用户操作会重置计时 // @author damu // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_notification // @run-at document-idle // @license MIT // ==/UserScript== (function() { 'use strict'; const DEFAULT_SCROLL = 5, DEFAULT_REFRESH = 20, DEFAULT_ACTIVITY = 1; let scrollTimer, refreshTimer, lastActivityTime = Date.now(); let globalEnabled = GM_getValue('globalEnabled', true); let sites = GM_getValue('keepAliveSites', []); // 修复旧数据格式:如果sites是字符串数组,转换为对象数组 if (sites.length > 0 && typeof sites[0] === 'string') { sites = sites.map(url => ({ url: url, enabled: true, scroll: DEFAULT_SCROLL, refresh: DEFAULT_REFRESH, activity: DEFAULT_ACTIVITY })); GM_setValue('keepAliveSites', sites); } GM_registerMenuCommand("网站保活管理", openManagerUI); GM_registerMenuCommand("添加当前网站", addCurrentSite); function addCurrentSite() { const currentUrl = window.location.origin + window.location.pathname; const sitePattern = currentUrl + (window.location.pathname.endsWith('/') ? '*' : '/*'); if (!sites.some(s => s.url === sitePattern)) { sites.push({url: sitePattern, enabled: true, scroll: DEFAULT_SCROLL, refresh: DEFAULT_REFRESH, activity: DEFAULT_ACTIVITY}); GM_setValue('keepAliveSites', sites); GM_notification({ text: `已添加 ${sitePattern}`, timeout: 2000 }); if (globalEnabled) initKeepAlive(); } else { GM_notification({ text: '网站已存在', timeout: 2000 }); } } function openManagerUI() { if (!document.getElementById('keepAliveManager')) createManagerUI(); document.getElementById('keepAliveOverlay').style.display = 'block'; document.getElementById('keepAliveManager').style.display = 'block'; } function closeManagerUI() { document.getElementById('keepAliveOverlay').style.display = 'none'; document.getElementById('keepAliveManager').style.display = 'none'; } function addSiteFromUI() { const url = document.getElementById('siteUrl').value.trim(); if (url && !sites.some(s => s.url === url)) { sites.push({url: url, enabled: true, scroll: DEFAULT_SCROLL, refresh: DEFAULT_REFRESH, activity: DEFAULT_ACTIVITY}); renderSiteList(); document.getElementById('siteUrl').value = ''; } } function saveConfig() { globalEnabled = document.getElementById('globalToggle').checked; GM_setValue('keepAliveSites', sites); GM_setValue('globalEnabled', globalEnabled); GM_notification({ text: '已保存', timeout: 1500 }); closeManagerUI(); clearTimers(); if (globalEnabled && checkSite()) initKeepAlive(); } function createManagerUI() { const overlay = document.createElement('div'); overlay.id = 'keepAliveOverlay'; overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:9999;display:none'; overlay.onclick = closeManagerUI; const manager = document.createElement('div'); manager.id = 'keepAliveManager'; manager.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:400px;background:white;border-radius:8px;z-index:10000;display:none'; manager.innerHTML = ` <div style="background:#3498db;color:white;padding:15px;border-radius:8px 8px 0 0;display:flex;justify-content:space-between;align-items:center"> <h3 style="margin:0">网站保活管理</h3> <button id="closeBtn" style="background:none;border:none;color:white;font-size:20px;cursor:pointer">×</button> </div> <div style="padding:15px"> <div style="margin-bottom:15px"> <label><input type="checkbox" id="globalToggle" ${globalEnabled ? 'checked' : ''}> 全局启用</label> </div> <div style="margin-bottom:15px"> <input type="text" id="siteUrl" placeholder="输入网站URL" style="width:100%;padding:8px;border:1px solid #ddd;border-radius:4px;margin-bottom:10px"> <button id="addBtn" style="background:#3498db;color:white;border:none;padding:8px 15px;border-radius:4px;cursor:pointer;width:100%">添加网站</button> </div> <div id="siteList" style="max-height:300px;overflow-y:auto"></div> </div> <div style="padding:15px;background:#f5f5f5;border-radius:0 0 8px 8px;text-align:right"> <button id="saveBtn" style="background:#2ecc71;color:white;border:none;padding:8px 15px;border-radius:4px;cursor:pointer;margin-right:10px">保存</button> <button id="cancelBtn" style="background:#e74c3c;color:white;border:none;padding:8px 15px;border-radius:4px;cursor:pointer">取消</button> </div> `; document.body.appendChild(overlay); document.body.appendChild(manager); document.getElementById('closeBtn').onclick = closeManagerUI; document.getElementById('addBtn').onclick = addSiteFromUI; document.getElementById('saveBtn').onclick = saveConfig; document.getElementById('cancelBtn').onclick = closeManagerUI; renderSiteList(); } function renderSiteList() { const siteListDiv = document.getElementById('siteList'); if (!siteListDiv) return; siteListDiv.innerHTML = sites.length ? '' : '<div style="text-align:center;color:#666;padding:20px">暂无网站</div>'; sites.forEach((site, index) => { const siteItem = document.createElement('div'); siteItem.style.cssText = 'padding:10px;border-bottom:1px solid #eee;display:flex;align-items:center;justify-content:space-between'; siteItem.innerHTML = ` <div style="flex:1"> <label style="display:flex;align-items:center;cursor:pointer"> <input type="checkbox" ${site.enabled ? 'checked' : ''} style="margin-right:8px"> <span style="font-size:12px">${site.url}</span> </label> </div> <button style="background:#e74c3c;color:white;border:none;padding:4px 8px;border-radius:3px;cursor:pointer;font-size:12px">删除</button> `; const checkbox = siteItem.querySelector('input[type="checkbox"]'); checkbox.onchange = function() { sites[index].enabled = this.checked; }; const deleteBtn = siteItem.querySelector('button'); deleteBtn.onclick = function() { sites.splice(index, 1); renderSiteList(); }; siteListDiv.appendChild(siteItem); }); } function clearTimers() { clearTimeout(scrollTimer); clearTimeout(refreshTimer); } function checkSite() { const currentUrl = window.location.href; return sites.some(site => site.enabled && new RegExp('^' + site.url.replace(/\*/g, '.*') + '$').test(currentUrl)); } function getCurrentSiteSettings() { const currentUrl = window.location.href; return sites.find(site => site.enabled && new RegExp('^' + site.url.replace(/\*/g, '.*') + '$').test(currentUrl)); } function simulateScroll() { window.scrollBy(0, 200); setTimeout(() => window.scrollBy(0, -100), 1000); } function refreshPage() { const settings = getCurrentSiteSettings(); if (settings && Date.now() - lastActivityTime > settings.activity * 60000) { window.location.reload(); } else { resetTimers(); } } function resetTimers() { const settings = getCurrentSiteSettings(); if (!settings) return; lastActivityTime = Date.now(); clearTimers(); scrollTimer = setTimeout(simulateScroll, settings.scroll * 60000); refreshTimer = setTimeout(refreshPage, settings.refresh * 60000); } function initKeepAlive() { ['mousemove', 'keypress', 'click', 'scroll'].forEach(event => { document.addEventListener(event, () => { lastActivityTime = Date.now(); }, {passive: true}); }); resetTimers(); } // 初始化 if (globalEnabled && checkSite()) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initKeepAlive); } else { initKeepAlive(); } } })();