// ==UserScript== // @name 网站访问确认脚本 // @namespace https://github.com/liucong2013/userscript-site-access-check // @version 1.8 // @icon data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAgACADASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAABgcDBQgE/8QAKxAAAQMEAQQBAwQDAAAAAAAAAQIDBAUGBxEIABIhQRQxMlETFiJhJEKh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAwACBf/EACMRAAEDAwMFAQAAAAAAAAAAAAECAxEABBIhMUEFFFGx8GH/2gAMAwEAAhEDEQA/ANgZfy7k6+8nO8duO0qLAq0GOmRdN0vth1qiMrH8Wm0+Qp9QIPsjYA0QpSONjgFjCqI+fkO+L9u+uOjukVKbXXG1KX7UhCPtH4BKtfnoS4tXz+yePN952l0OTW69X7tqUyohr7ysOhtAdVolDSNqUTo9oUfHno4urmdaiMdR6taUZTt01EFhNMeSVfBdGgpbhH3o2R2dvlewPGla248GTgDEVx7nqllaE90uDGUHxtpwT+b0KV+x8v8AFESLvxBkCq5BsuiJTIr1l12UmRNiQyCVPxngO5OgFK12gaSSQsA60/YF9W5kyzaTfdpTDKpNZjJkxnCNKAPgoUPS0qBSoeikjpM8cMKXRR587LOT6hMduS4WVIXCeWdpZcIJMgfRSzoab+1seNb8JqODiRRIWVMfQVE0i1cgVKHTBvYbZVpX6af6BH/T1JUXUZEQabp1w7cNJdcbwymATJjgnxI44qis2vwOJmZrlxhkEJgY3yLU3a3bFYfT/hxJjoAkQn1HwgE60T4ACSfCiUtezeM2Lrav1zI9HZMhpwJkUyCSlcSE4ryXWtb7vqOzZIRs9vrTIvKybTyFb8m1r1t+FWaVLGnYstoLQT6UPaVD0oEEeiOkCOCto0hS49hZhylaVMdJKqZTLhV8dIP+qApJKRr8k9Sgh2CrcUj9k08pKnUBWJkTuD99oKNeSPJSy+P1oSZk+fGlXLJZUKRRkuAvSHiP4rWkHaGgfKlHW9aG1EDqs4WWXFtXBVLq5r8Ot1O75D1yVWfEdDjbkuQrakBQ9oCQhQ9LSvqexOGuB7IZqS37XdueoVeO5FnVO45BnynmljS0hSvCNj2gBX99IJii5N4G5Oaatyn1e78O3dPS38NlCn5NPkrOgAB9HgNaPhLyU6VpaQekASpOCd/dKoqSoLWNPVf/2Q== // @description 限制指定主域名及其所有子域名的访问,显示确认页面(无刷新),支持30分钟、今日内和本次会话不再提示,受限列表存储在 GM_Value 中,已确认页面显示倒计时,支持通过菜单添加当前域名到限制列表 // @author lc cong // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @run-at document_start // @noframes // @supportURL https://raw.githubusercontent.com/liucong2013/userscript-site-access-check/refs/heads/main/README.md // @downloadURL none // ==/UserScript== (function() { 'use strict'; if (window.top !== window.self) { console.log("脚本在 iframe 中运行,退出。"); return; } // --- 配置 --- const RESTRICTED_DOMAINS_KEY = 'my_restricted_domains'; const LOCAL_CONFIRM_KEY_PREFIX = 'confirmed_access_'; // --- 工具函数 --- function getRestrictedBaseDomains() { const domainsJson = GM_getValue(RESTRICTED_DOMAINS_KEY, '[]'); try { const domains = JSON.parse(domainsJson); return Array.isArray(domains) ? domains : []; } catch (e) { console.error("解析受限域名列表失败:", e); GM_deleteValue(RESTRICTED_DOMAINS_KEY); return []; } } function setRestrictedBaseDomains(domainsArray) { GM_setValue(RESTRICTED_DOMAINS_KEY, JSON.stringify(domainsArray)); } function getBaseDomain(hostname) { if (!hostname) return ''; const parts = hostname.split('.'); if (parts.length <= 2) return hostname; const secondLast = parts[parts.length - 2]; const commonTldParts = ['co', 'com', 'org', 'net', 'gov', 'edu', 'ac']; if (commonTldParts.includes(secondLast) && parts.length >= 3) { return parts.slice(-3).join('.'); } return parts.slice(-2).join('.'); } function findMatchingRestrictedDomain(hostname, restrictedDomains) { return restrictedDomains.find(baseDomain => hostname === baseDomain || hostname.endsWith('.' + baseDomain) ); } function getEndOfTodayTimestamp() { const now = new Date(); return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999).getTime(); } function isLocalConfirmedAndNotExpired(domainKey) { const storedData = GM_getValue(LOCAL_CONFIRM_KEY_PREFIX + domainKey, null); if (!storedData) return false; try { const { timestamp, expiryType } = JSON.parse(storedData); const now = Date.now(); if (expiryType === '30min') return now < timestamp + 30 * 60 * 1000; if (expiryType === '5min') return now < timestamp + 5 * 60 * 1000; if (expiryType === 'today') { const todayStart = new Date().setHours(0, 0, 0, 0); return timestamp >= todayStart && now < getEndOfTodayTimestamp(); } return false; } catch (e) { console.error("解析确认状态失败:", e); GM_deleteValue(LOCAL_CONFIRM_KEY_PREFIX + domainKey); return false; } } function setLocalConfirmed(domainKey, expiryType) { const confirmInfo = { timestamp: Date.now(), expiryType }; GM_setValue(LOCAL_CONFIRM_KEY_PREFIX + domainKey, JSON.stringify(confirmInfo)); return confirmInfo; } function showToast(message) { const toast = document.createElement('div'); toast.textContent = message; GM_addStyle(` #gm-toast { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background-color: #333; color: white; padding: 10px 20px; border-radius: 5px; z-index: 999999; font-size: 14px; } `); toast.id = 'gm-toast'; document.body.appendChild(toast); setTimeout(() => toast.remove(), 3000); } function showRestrictionOverlay(hostname, domainToConfirm) { const overlay = document.createElement('div'); overlay.id = 'restriction-overlay'; GM_addStyle(` #restriction-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); z-index: 9999998; display: flex; justify-content: center; align-items: center; font-family: sans-serif; } .restriction-container { background-color: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); text-align: center; max-width: 500px; } .restriction-container h1 { color: #d9534f; margin-bottom: 20px; } .restriction-container p { color: #555; margin-bottom: 30px; line-height: 1.6; } .button-container button { background-color: #5cb85c; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; font-size: 15px; margin: 5px; transition: background-color 0.3s ease; } .button-container button:hover { background-color: #4cae4c; } `); overlay.innerHTML = `
您正尝试访问的网站 ${hostname} 已被标记为受限。请确认您希望继续访问,并选择本次确认的有效时长。