Last active 1 week ago

用于获取相关信息,注意需要先行在.md划定表格并填入预填项,自行填入KEY,别用我的,额度不够

custom.css Raw
1/* ===== 隐私政策页面信息加载动画 ===== */
2.privacy-cell-loading {
3 position: relative;
4 color: transparent !important;
5 background: linear-gradient(
6 90deg,
7 var(--anzhiyu-secondbg) 25%,
8 var(--anzhiyu-gray-op) 50%,
9 var(--anzhiyu-secondbg) 75%
10 );
11 background-size: 200% 100%;
12 animation: privacy-shimmer 1.5s ease-in-out infinite;
13 border-radius: 4px;
14 min-width: 80px;
15 display: inline-block;
16}
17
18@keyframes privacy-shimmer {
19 0% { background-position: 200% 0; }
20 100% { background-position: -200% 0; }
21}
22
23#article-container table td {
24 transition: background-color 0.3s ease, color 0.3s ease;
25}
index.md Raw
类型 信息
网络信息
IP地址 获取中...
国家 获取中...
省份 获取中...
城市 获取中...
运营商 获取中...
设备信息
操作系统 获取中...
浏览器 获取中...
privacy-info.js Raw
1/**
2 * 隐私政策页面 - 动态展示访客信息
3 * 使用腾讯地图IP定位API + ipapi.co获取网络信息
4 * 使用navigator.userAgent解析设备信息
5 */
6(function () {
7 'use strict';
8
9 const CONFIG = {
10 TENCENT_KEY: 'FXNBZ-T5DCB-ABWUU-NXPTT-4AXGH-IUBAQ',
11 CACHE_KEY: 'privacy_ip_cache',
12 CACHE_TTL: 1000 * 60 * 60, // 1小时
13 };
14
15 // ========== 页面检测 ==========
16 function isPrivacyPage() {
17 const p = window.location.pathname;
18 return p === '/privacy/' || p === '/privacy' || p === '/privacy/index.html';
19 }
20
21 // ========== 缓存 ==========
22 function getFromCache() {
23 try {
24 const raw = localStorage.getItem(CONFIG.CACHE_KEY);
25 if (!raw) return null;
26 const { data, ts } = JSON.parse(raw);
27 if (Date.now() - ts > CONFIG.CACHE_TTL) {
28 localStorage.removeItem(CONFIG.CACHE_KEY);
29 return null;
30 }
31 return data;
32 } catch {
33 return null;
34 }
35 }
36
37 function setCache(data) {
38 try {
39 localStorage.setItem(CONFIG.CACHE_KEY, JSON.stringify({ data, ts: Date.now() }));
40 } catch { /* quota exceeded, ignore */ }
41 }
42
43 // ========== 腾讯地图IP定位 (JSONP) ==========
44 function fetchTencentIP() {
45 return new Promise((resolve, reject) => {
46 const cb = `_privacy_qqmap_${Date.now()}`;
47 const script = document.createElement('script');
48 script.src = `https://apis.map.qq.com/ws/location/v1/ip?key=${encodeURIComponent(CONFIG.TENCENT_KEY)}&output=jsonp&callback=${cb}`;
49
50 window[cb] = (res) => {
51 cleanup();
52 if (res.status !== 0) return reject(new Error(res.message));
53 const { ad_info } = res.result;
54 resolve({
55 ip: res.result.ip || '',
56 country: ad_info.nation || '',
57 province: ad_info.province || '',
58 city: ad_info.city || '',
59 });
60 };
61
62 script.onerror = () => { cleanup(); reject(new Error('JSONP request failed')); };
63
64 function cleanup() {
65 document.head.removeChild(script);
66 delete window[cb];
67 }
68
69 document.head.appendChild(script);
70 });
71 }
72
73 // ========== 运营商检测 (ipapi.co, HTTPS) ==========
74 function fetchISP() {
75 return fetch('https://ipapi.co/json/')
76 .then(r => r.json())
77 .then(d => d.org || '获取失败');
78 }
79
80 // ========== UA解析 ==========
81 function parseUserAgent() {
82 const ua = navigator.userAgent;
83 return { os: detectOS(ua), browser: detectBrowser(ua) };
84 }
85
86 function detectOS(ua) {
87 if (/Windows NT 10\.0/.test(ua)) return 'Windows 10/11';
88 if (/Windows NT 6\.3/.test(ua)) return 'Windows 8.1';
89 if (/Windows NT 6\.2/.test(ua)) return 'Windows 8';
90 if (/Windows NT 6\.1/.test(ua)) return 'Windows 7';
91 if (/Windows/.test(ua)) return 'Windows';
92
93 const macMatch = ua.match(/Mac OS X ([\d_]+)/);
94 if (macMatch) return 'macOS ' + macMatch[1].replace(/_/g, '.');
95
96 const androidMatch = ua.match(/Android ([\d.]+)/);
97 if (androidMatch) return 'Android ' + androidMatch[1];
98
99 const iosMatch = ua.match(/OS ([\d_]+)/);
100 if (/iPhone|iPad|iPod/.test(ua) && iosMatch) return 'iOS ' + iosMatch[1].replace(/_/g, '.');
101
102 if (/Linux/.test(ua)) return 'Linux';
103 return '未知';
104 }
105
106 function detectBrowser(ua) {
107 if (/Edg\//.test(ua)) return 'Edge ' + (ua.match(/Edg\/([\d.]+)/) || [])[1];
108 if (/OPR\//.test(ua)) return 'Opera ' + (ua.match(/OPR\/([\d.]+)/) || [])[1];
109 if (/Chrome\//.test(ua)) return 'Chrome ' + (ua.match(/Chrome\/([\d.]+)/) || [])[1];
110 if (/Firefox\//.test(ua)) return 'Firefox ' + (ua.match(/Firefox\/([\d.]+)/) || [])[1];
111 if (/Safari\//.test(ua)) return 'Safari ' + (ua.match(/Version\/([\d.]+)/) || [])[1];
112 return '未知';
113 }
114
115 // ========== 表格操作 ==========
116 function findPrivacyTable() {
117 const tables = document.querySelectorAll('#article-container table');
118 for (const table of tables) {
119 const rows = table.querySelectorAll('tbody tr');
120 for (const row of rows) {
121 const firstCell = row.querySelector('td:first-child');
122 if (firstCell && firstCell.textContent.trim() === 'IP地址') {
123 return table;
124 }
125 }
126 }
127 return null;
128 }
129
130 function getCellByLabel(table, label) {
131 const rows = table.querySelectorAll('tbody tr');
132 for (const row of rows) {
133 const firstCell = row.querySelector('td:first-child');
134 if (firstCell && firstCell.textContent.trim() === label) {
135 return row.querySelector('td:nth-child(2)');
136 }
137 }
138 return null;
139 }
140
141 function fillCell(table, label, value) {
142 const cell = getCellByLabel(table, label);
143 if (!cell) return;
144 cell.classList.remove('privacy-cell-loading');
145 cell.textContent = value || '获取失败';
146 }
147
148 function addLoadingClass(table) {
149 const labels = ['IP地址', '国家', '省份', '城市', '运营商', '操作系统', '浏览器'];
150 labels.forEach(label => {
151 const cell = getCellByLabel(table, label);
152 if (cell) cell.classList.add('privacy-cell-loading');
153 });
154 }
155
156 // ========== 主逻辑 ==========
157 function init() {
158 if (!isPrivacyPage()) return;
159
160 const table = findPrivacyTable();
161 if (!table) return;
162
163 addLoadingClass(table);
164
165 const cached = getFromCache();
166 if (cached) {
167 fillAll(table, cached);
168 return;
169 }
170
171 // 并行获取数据
172 Promise.allSettled([fetchTencentIP(), fetchISP()]).then(([tencentRes, ispRes]) => {
173 const tencent = tencentRes.status === 'fulfilled' ? tencentRes.value : {};
174 const isp = ispRes.status === 'fulfilled' ? ispRes.value : '获取失败';
175 const ua = parseUserAgent();
176
177 const data = {
178 ip: tencent.ip || '获取失败',
179 country: tencent.country || '获取失败',
180 province: tencent.province || '获取失败',
181 city: tencent.city || '获取失败',
182 isp: isp,
183 os: ua.os,
184 browser: ua.browser,
185 };
186
187 fillAll(table, data);
188 setCache(data);
189 });
190 }
191
192 function fillAll(table, data) {
193 fillCell(table, 'IP地址', data.ip);
194 fillCell(table, '国家', data.country);
195 fillCell(table, '省份', data.province);
196 fillCell(table, '城市', data.city);
197 fillCell(table, '运营商', data.isp);
198 fillCell(table, '操作系统', data.os);
199 fillCell(table, '浏览器', data.browser);
200 }
201
202 // ========== 初始化(含Pjax兼容) ==========
203 function safeInit() {
204 // 延迟执行,等待主题的 addTableWrap() 完成
205 setTimeout(init, 100);
206 }
207
208 document.addEventListener('DOMContentLoaded', safeInit);
209 document.addEventListener('pjax:complete', safeInit);
210})();