您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
基于剩余天数主动预警PT站点的活跃度,UI分级高亮,并在最后一天弹窗警告。目前已经在安全时间内减去了2天缓冲
// ==UserScript== // @name PT 站点活跃度预警系统 (最终修复版) // @namespace http://tampermonkey.net/ // @version 1.5 // @description 基于剩余天数主动预警PT站点的活跃度,UI分级高亮,并在最后一天弹窗警告。目前已经在安全时间内减去了2天缓冲 // @author Gemini & YourName // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_openInTab // @license MIT // ==/UserScript== (function() { 'use strict'; // --- 1. 用户配置 --- const siteSettings = [ // --- 重要的网站 --- { domain: 'pterclub.com', days: 58, name: '猫站', important: true }, { domain: 'open.cd', days: 88, name: '皇后', important: true }, { domain: 'ourbits.club', days: 148, name: '我堡', important: true }, { domain: 'hdhome.org', days: 58, name: '家园', important: true }, { domain: 'chdbits.xyz', days: 43, name: 'CHD', important: true }, { domain: 'audiences.me', days: 98, name: '观众', important: true }, //根据用户等级修改!!! { domain: 'hhanclub.top', days: 28, name: '憨憨', important: true }, { domain: 'pt.keepfrds.com', days: 33, name: '朋友', important: true }, { domain: 'totheglory.im', days: 80, name: 'TTG', important: true }, //12周 { domain: 'ob.m-team.cc', days: 38, name: '馒头', important: true }, // --- 其他网站 --- { domain: 'kufei.org', days: 148, name: '库非' }, { domain: 'hdtime.org', days: 148, name: 'HD时光' }, //暂时打不开网站 { domain: '1ptba.com', days: 148, name: '1PT' }, { domain: 'ptcafe.club', days: 178, name: '咖啡' }, { domain: 'rousi.zip', days: 148, name: '肉丝' }, { domain: 'ptlgs.org', days: 28, name: '劳改所' }, //超过30天不活跃的账号将被系统自动封禁。 活跃判定方法:当有未读公告时,需手动确认公告已读才算活跃;当没有未读公告时,需访问首页才算活跃。 { domain: 'hdfans.org', days: 88, name: '红豆饭' }, { domain: 'sunnypt.top', days: 148, name: 'Sunny' }, { domain: 'www.agsvpt.com', days: 148, name: '末日' }, { domain: 'qingwapt.com', days: 88, name: '青蛙' }, { domain: 'xingtan.one', days: 58, name: '杏坛' }, { domain: 'u2.dmhy.org', days: 88, name: 'U2动漫' }, { domain: 'zmpt.cc', days: 43, name: '织梦' }, { domain: 'hdkyl.in', days: 178, name: '麒麟' }, { domain: 'ubits.club', days: 58, name: '你堡' } ]; // -------------------- // --- 2. 脚本核心逻辑 --- const STORAGE_KEY = 'pt_tracker_data'; const GLOBAL_ALERT_KEY = 'pt_tracker_global_alert_date'; async function loadData(key, defaultValue) { return await GM_getValue(key, defaultValue); } async function saveData(key, value) { await GM_setValue(key, value); } async function checkAndUpdateCurrentSite() { const storedData = await loadData(STORAGE_KEY, {}); const currentHost = window.location.hostname; for (const site of siteSettings) { if (currentHost === site.domain || currentHost.endsWith('.' + site.domain)) { const now = new Date().toISOString(); if (storedData[site.domain] !== now) { storedData[site.domain] = now; await saveData(STORAGE_KEY, storedData); console.log(`[PT Tracker] 已刷新站点: ${site.name || site.domain}`); } return; } } } // --- 3. UI 创建与更新 (已修复) --- function createUI() { GM_addStyle(` #pt-tracker-container { position: fixed; top: 10px; right: 10px; z-index: 2147483647; } #pt-tracker-ui { padding: 2px 8px; min-width: 20px; height: 20px; background-color: #f0f0f0; border: 1px solid #ccc; border-radius: 4px; display: flex; justify-content: center; align-items: center; font-size: 12px; font-family: monospace; cursor: pointer; box-shadow: 0 0 5px rgba(0,0,0,0.2); } #pt-tracker-tooltip { visibility: hidden; position: absolute; top: 100%; right: 0; padding-top: 5px; background-color: transparent; opacity: 0; transition: opacity 0.3s, visibility 0.3s; pointer-events: none; } #pt-tracker-tooltip-content { background-color: white; color: black; padding: 10px; border-radius: 4px; font-size: 12px; font-family: sans-serif; white-space: nowrap; text-align: left; border: 1px solid #ddd; max-height: 80vh; overflow-y: auto; pointer-events: auto; box-shadow: 0 2px 8px rgba(0,0,0,0.15); } #pt-tracker-tooltip-content a { text-decoration: none; } #pt-tracker-tooltip-content a:hover { text-decoration: underline; } #pt-tracker-container:hover #pt-tracker-tooltip { visibility: visible; opacity: 1; } #pt-tracker-open-all { display: block; margin-top: 8px; padding: 4px; background-color: #007bff; color: white; text-align: center; border-radius: 3px; cursor: pointer; font-weight: bold;} #pt-tracker-open-all:hover { background-color: #0056b3; } `); const container = document.createElement('div'); container.id = 'pt-tracker-container'; const uiCounter = document.createElement('div'); uiCounter.id = 'pt-tracker-ui'; const tooltip = document.createElement('div'); tooltip.id = 'pt-tracker-tooltip'; tooltip.innerHTML = `<div id="pt-tracker-tooltip-content"></div>`; container.appendChild(uiCounter); container.appendChild(tooltip); document.body.appendChild(container); return { uiCounter: uiCounter, tooltipContent: tooltip.querySelector('#pt-tracker-tooltip-content') }; } async function updateUI({ uiCounter, tooltipContent }) { const storedData = await loadData(STORAGE_KEY, {}); const now = new Date(); const siteStates = []; for (const site of siteSettings) { const lastVisitStr = storedData[site.domain]; let state = { ...site, tier: 'green', statusText: '', daysRemaining: Infinity }; if (lastVisitStr) { const daysSinceVisit = Math.floor((now - new Date(lastVisitStr)) / (1000 * 60 * 60 * 24)); const daysRemaining = site.days - daysSinceVisit; state.daysRemaining = daysRemaining; if (daysRemaining <= 3) state.tier = 'red'; else if (daysRemaining <= 6) state.tier = 'pink'; state.statusText = daysRemaining >= 0 ? `(剩余安全期: ${daysRemaining}天)` : `(已过期: ${-daysRemaining}天)`; } else { state.tier = 'red'; state.statusText = `(从未访问过)`; } siteStates.push(state); } const greenSites = siteStates.filter(s => s.tier === 'green').sort((a, b) => b.daysRemaining - a.daysRemaining); const pinkSites = siteStates.filter(s => s.tier === 'pink').sort((a,b) => a.daysRemaining - b.daysRemaining); const redSites = siteStates.filter(s => s.tier === 'red').sort((a,b) => a.daysRemaining - b.daysRemaining); let contentHTML = ''; const atRiskDomains = []; const renderSite = (site) => { const displayName = site.name || site.domain; const nameColor = site.important ? 'red' : 'black'; let statusColor = 'grey'; if (site.tier === 'red') statusColor = 'red'; else if (site.tier === 'pink') statusColor = 'hotpink'; else if (site.tier === 'green') statusColor = 'green'; return `<div><a href="https://${site.domain}" target="_blank" style="color:${nameColor}; font-weight:${site.important ? 'bold' : 'normal'};">${displayName}</a> <span style="color:${statusColor};">${site.statusText}</span></div>`; }; redSites.forEach(s => { contentHTML += renderSite(s); atRiskDomains.push(s.domain); }); pinkSites.forEach(s => { contentHTML += renderSite(s); atRiskDomains.push(s.domain); }); if ((redSites.length > 0 || pinkSites.length > 0) && greenSites.length > 0) { contentHTML += '<hr style="margin: 5px 0; border: none; border-top: 1px solid #eee;">'; } greenSites.forEach(s => { contentHTML += renderSite(s); }); if (atRiskDomains.length > 0) { contentHTML += `<div id="pt-tracker-open-all">一键打开 ${atRiskDomains.length} 个风险站点</div>`; } uiCounter.innerHTML = ` <span style="color: green; font-weight: bold;">${greenSites.length}</span> <span style="margin: 0 2px;">/</span> <span style="color: hotpink; font-weight: bold;">${pinkSites.length}</span> <span style="margin: 0 2px;">/</span> <span style="color: red; font-weight: bold;">${redSites.length}</span> `; tooltipContent.innerHTML = contentHTML; const openAllButton = document.getElementById('pt-tracker-open-all'); if (openAllButton) { openAllButton.addEventListener('click', () => { atRiskDomains.forEach(domain => GM_openInTab(`https://${domain}`, { active: false })); }); } } async function checkAndShowAlerts() { const now = new Date(); const todayStr = now.toISOString().split('T')[0]; const lastAlertDate = await loadData(GLOBAL_ALERT_KEY, ''); if (lastAlertDate === todayStr) { return; } const storedData = await loadData(STORAGE_KEY, {}); let needsAlert = false; for (const site of siteSettings) { const lastVisitStr = storedData[site.domain]; let daysRemaining = -1; if (lastVisitStr) { daysRemaining = site.days - Math.floor((now - new Date(lastVisitStr)) / (1000 * 60 * 60 * 24)); } if (daysRemaining <= 1) { needsAlert = true; break; } } if (needsAlert) { alert('您有PT站点不活跃,即将封禁!'); await saveData(GLOBAL_ALERT_KEY, todayStr); } } async function main() { const uiElements = createUI(); await checkAndUpdateCurrentSite(); await updateUI(uiElements); await checkAndShowAlerts(); } if (document.readyState === 'complete') { main(); } else { window.addEventListener('load', main); } })();