你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
(我已經安裝了使用者樣式管理器,讓我安裝!)
// ==UserScript==
// @name NGA论坛WOW封禁检测脚本
// @namespace http://tampermonkey.net/
// @version 2.0.0
// @description 检测NGA论坛中的WOW角色是否被封禁(基于RMT处罚名单)
// @author 逗逗你德
// @license GNU GPLv3
// @match https://ngabbs.com/read.php?tid=*
// @match https://bbs.nga.cn/read.php?tid=*
// @match http://ngabbs.com/read.php?tid=*
// @match http://bbs.nga.cn/read.php?tid=*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// @grant GM_getResourceText
// @run-at document-idle
// @resource banList https://gist.githubusercontent.com/Hans0924/146ac44e638e86c1b1320c39531b4184/raw/b45f546563794bd234809ea5aa7cc7dd1d141c84/wow-cn-rmt-ban-list.json
// ==/UserScript==
(function() {
'use strict';
console.log('NGA论坛WOW封禁检测脚本已加载');
// 封禁名单数据
let banList = [];
let isDataLoaded = false;
// 已检测的角色记录(避免重复检测)
let detectedCharacters = new Set();
// 已知被封禁的角色记录(用于给新回复添加警告)
let bannedCharacters = new Map(); // 使用Map存储角色ID和封禁记录
// 初始化函数
function init() {
console.log('初始化WOW封禁检测功能...');
// 添加自定义样式
addCustomStyles();
// 加载封禁名单数据
loadBanList();
// 等待页面加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', startDetection);
} else {
startDetection();
}
}
// 添加自定义样式
function addCustomStyles() {
GM_addStyle(`
/* WOW封禁检测样式 */
.nga-ban-warning {
background: linear-gradient(135deg, #ff6b6b, #ff5252);
color: white;
padding: 6px 12px;
margin: 5px 0;
border-radius: 20px;
font-size: 12px;
font-weight: bold;
text-align: center;
box-shadow: 0 2px 8px rgba(255, 107, 107, 0.3);
border: 2px solid #ff4444;
animation: banWarningPulse 2s ease-in-out infinite alternate;
}
@keyframes banWarningPulse {
0% { box-shadow: 0 2px 8px rgba(255, 107, 107, 0.3); }
100% { box-shadow: 0 4px 16px rgba(255, 107, 107, 0.6); }
}
.nga-ban-warning:before {
content: "⚠️ ";
font-size: 14px;
}
.nga-loading-status {
position: fixed;
top: 10px;
right: 10px;
background: #2196F3;
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 12px;
z-index: 10000;
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.3);
}
.nga-detection-stats {
position: fixed;
bottom: 10px;
right: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 8px 16px;
border-radius: 15px;
font-size: 11px;
z-index: 10000;
max-width: 200px;
}
`);
}
// 加载封禁名单数据
function loadBanList() {
showLoadingStatus('正在加载封禁名单...');
try {
const resourceData = GM_getResourceText('banList');
if (resourceData) {
banList = JSON.parse(resourceData);
isDataLoaded = true;
console.log(`封禁名单加载成功,共 ${banList.length} 条记录`);
hideLoadingStatus();
startDetection();
} else {
console.error('无法获取封禁名单资源');
showLoadingStatus('封禁名单加载失败', true);
}
} catch (error) {
console.error('加载封禁名单失败:', error);
showLoadingStatus('封禁名单加载失败', true);
}
}
// 显示加载状态
function showLoadingStatus(message, isError = false) {
let statusEl = document.getElementById('nga-loading-status');
if (!statusEl) {
statusEl = document.createElement('div');
statusEl.id = 'nga-loading-status';
statusEl.className = 'nga-loading-status';
document.body.appendChild(statusEl);
}
statusEl.textContent = message;
statusEl.style.background = isError ? '#ff5252' : '#2196F3';
}
// 隐藏加载状态
function hideLoadingStatus() {
const statusEl = document.getElementById('nga-loading-status');
if (statusEl) {
statusEl.remove();
}
}
// 开始检测
function startDetection() {
if (!isDataLoaded) {
console.log('封禁名单未加载,等待中...');
return;
}
console.log('开始检测WOW角色封禁状态...');
detectBannedPlayers();
// 设置页面变化监听
setupPageObserver();
}
// 检测被封禁的玩家
function detectBannedPlayers() {
const spans = document.querySelectorAll('span.block_txt_c3');
console.log(`找到 ${spans.length} 个角色信息元素`);
let checkedCount = 0;
let bannedCount = 0;
let newCheckedCount = 0;
let newBannedCount = 0;
let hasNewWarnings = false; // 追踪是否有新的警告被添加
spans.forEach(span => {
const playerInfo = parsePlayerInfo(span);
if (playerInfo) {
const characterId = `${playerInfo.serverName}|${playerInfo.characterName}`;
// 检查是否已经有封禁警告标记
if (span.closest('.clickextend')?.querySelector('.nga-ban-warning')) {
return; // 跳过已经标记过的span
}
// 如果是已知的被封禁角色,直接添加警告(不重复计入统计)
if (bannedCharacters.has(characterId)) {
const banRecord = bannedCharacters.get(characterId);
addBanWarning(span, banRecord);
hasNewWarnings = true;
console.log(`为已知被封禁角色添加警告: ${characterId}`);
return;
}
// 如果是已检测过但未被封禁的角色,跳过
if (detectedCharacters.has(characterId)) {
return;
}
// 新角色,进行检测
detectedCharacters.add(characterId);
checkedCount++;
newCheckedCount++;
const isBanned = checkIfBanned(playerInfo);
if (isBanned) {
bannedCount++;
newBannedCount++;
bannedCharacters.set(characterId, isBanned); // 记录被封禁的角色
addBanWarning(span, isBanned);
hasNewWarnings = true;
console.log(`发现新的被封禁角色: ${characterId}`);
}
}
});
// 显示检测统计
if (newCheckedCount > 0 || hasNewWarnings) {
showDetectionStats(newCheckedCount, newBannedCount);
if (newCheckedCount > 0) {
console.log(`检测完成: 新检查了 ${newCheckedCount} 个角色,发现 ${newBannedCount} 个可能被封禁的角色`);
console.log(`总计: 已检查 ${detectedCharacters.size} 个角色,已知封禁 ${bannedCharacters.size} 个角色`);
}
if (hasNewWarnings && newCheckedCount === 0) {
console.log('为已知被封禁角色的新回复添加了警告标记');
}
} else {
console.log('本次检测未发现新的角色信息或封禁警告');
}
}
// 解析玩家信息
function parsePlayerInfo(span) {
const title = span.getAttribute('title');
if (!title) return null;
try {
// 解析title格式:"正式服 熊猫酒仙; 暗夜精灵德鲁伊 不夜之心 "艾泽拉斯肝王"; 装备等级714 成就点数25610 史诗钥石3017; https://wow.blizzard.cn/character/#/pandaren/不夜之心"
const parts = title.split(';');
if (parts.length < 2) return null;
// 第一部分:版本和服务器
const firstPart = parts[0].trim();
if (!firstPart.startsWith('正式服')) {
return null; // 只处理正式服
}
const serverName = firstPart.replace('正式服', '').trim();
// 第二部分:职业和角色名
const secondPart = parts[1].trim();
const match = secondPart.match(/^(.+?)\s+(.+?)\s+/);
if (!match) return null;
const characterName = match[2];
return {
serverName: serverName,
characterName: characterName,
element: span
};
} catch (error) {
console.error('解析玩家信息失败:', title, error);
return null;
}
}
// 检查是否被封禁
function checkIfBanned(playerInfo) {
const { serverName, characterName } = playerInfo;
// 在封禁名单中查找匹配的记录
const matches = banList.filter(banRecord => {
// 服务器名必须完全匹配
if (banRecord.server_name !== serverName) {
return false;
}
// 角色名匹配:考虑脱敏处理
return matchCharacterName(characterName, banRecord.character_name);
});
return matches.length > 0 ? matches[0] : null;
}
// 匹配角色名(考虑脱敏处理)
function matchCharacterName(actualName, bannedName) {
if (!actualName || !bannedName) return false;
// 长度必须相等
if (actualName.length !== bannedName.length) {
return false;
}
// 如果长度小于3,需要完全匹配
if (actualName.length < 3) {
return actualName === bannedName;
}
// 检查首尾字符是否匹配,中间字符是否为星号
const firstChar = actualName.charAt(0);
const lastChar = actualName.charAt(actualName.length - 1);
const bannedFirstChar = bannedName.charAt(0);
const bannedLastChar = bannedName.charAt(bannedName.length - 1);
// 首尾字符必须匹配
if (firstChar !== bannedFirstChar || lastChar !== bannedLastChar) {
return false;
}
// 检查中间是否都是星号(脱敏处理的特征)
const middlePart = bannedName.slice(1, -1);
return /^\*+$/.test(middlePart);
}
// 添加封禁警告
function addBanWarning(span, banRecord) {
// 找到目标容器:span的父元素的父元素(class为clickextend)
let targetContainer = span.parentElement?.parentElement;
// 如果没有找到clickextend,向上查找
if (!targetContainer || !targetContainer.classList.contains('clickextend')) {
let current = span;
while (current && current.parentElement) {
current = current.parentElement;
if (current.classList && current.classList.contains('clickextend')) {
targetContainer = current;
break;
}
}
}
if (!targetContainer) {
console.warn('未找到目标容器clickextend,使用span的父元素');
targetContainer = span.parentElement || span;
}
// 检查是否已经添加过警告
if (targetContainer.querySelector('.nga-ban-warning')) {
return;
}
// 创建警告元素
const warningEl = document.createElement('div');
warningEl.className = 'nga-ban-warning';
warningEl.innerHTML = `该玩家可能因RMT被处罚<br><small>来源: <a href="${banRecord.source_url}" target="_blank" style="color: #ffeb3b; text-decoration: underline;">${banRecord.source_url}</a></small>`;
warningEl.title = `封禁记录:角色名 ${banRecord.character_name},服务器 ${banRecord.server_name}\n数据来源:${banRecord.source_url}\n提取时间:${new Date(banRecord.extracted_date).toLocaleString()}`;
// 添加到目标容器
targetContainer.appendChild(warningEl);
}
// 显示检测统计
function showDetectionStats(newChecked, newBanned) {
let statsEl = document.getElementById('nga-detection-stats');
if (!statsEl) {
statsEl = document.createElement('div');
statsEl.id = 'nga-detection-stats';
statsEl.className = 'nga-detection-stats';
document.body.appendChild(statsEl);
}
// 计算总被封禁数量
const totalBanned = document.querySelectorAll('.nga-ban-warning').length;
statsEl.innerHTML = `
<div>🛡️ WOW封禁检测</div>
<div>总检查: ${detectedCharacters.size}</div>
<div>新检查: ${newChecked}</div>
<div>封禁角色: ${bannedCharacters.size}</div>
<div>封禁标记: ${totalBanned}</div>
<div>名单记录: ${banList.length}</div>
`;
// 重新设置透明度为完全可见
statsEl.style.opacity = '1';
// 3秒后自动变为半透明
setTimeout(() => {
if (statsEl) {
statsEl.style.opacity = '0.3';
}
}, 3000);
}
// 设置页面变化监听
function setupPageObserver() {
const observer = new MutationObserver(function(mutations) {
let shouldRedetect = false;
mutations.forEach(function(mutation) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
// 检查是否有新的角色信息元素
for (let node of mutation.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.classList?.contains('block_txt_c3') ||
node.querySelector?.('span.block_txt_c3')) {
shouldRedetect = true;
break;
}
}
}
}
});
if (shouldRedetect) {
console.log('检测到页面内容变化,重新执行封禁检测...');
setTimeout(detectBannedPlayers, 500);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// 启动脚本
init();
})();