// ==UserScript==
// @name KillUser-SmartTeach
// @namespace https://apanzinc.top/
// @version 2.0
// @description 屏蔽智教联盟论坛上不想看到的用户(帖子、月活榜单、通知、评论)
// @author apanzinc
// @match https://forum.smart-teach.cn/
// @match https://forum.smart-teach.cn/notifications
// @match https://forum.smart-teach.cn/d/*
// @match https://forum.smart-teach.cn/settings
// @icon http://youke.xn--y7xa690gmna.cn/s1/2026/01/18/696c93287a4a6.webp
// @grant none
// @homepage https://github.com/apanzinc/ST-KillUser
// @source https://github.com/apanzinc/ST-KillUser
// @license GPL3
// @contributionURL https://afdian.com/a/apanzinc
// @contributionAmount 0.00¥
// ==/UserScript==
(function() {
'use strict';
console.log(' /$$$$$$ /$$$$$$$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ ');
console.log(' /$$__ $$|__ $$__/ | $$ /$$/|__/| $$| $$| $$ | $$ ');
console.log('| $$ \__/ | $$ | $$ /$$/ /$$| $$| $$| $$ | $$ /$$$$$$$ /$$$$$$ /$$$$$$ ');
console.log('| $$$$$$ | $$ /$$$$$$| $$$$$/ | $$| $$| $$| $$ | $$ /$$_____/ /$$__ $$ /$$__ $$');
console.log(' \____ $$ | $$ |______/| $$ $$ | $$| $$| $$| $$ | $$| $$$$$$ | $$$$$$$$| $$ \__/');
console.log(' /$$ \ $$ | $$ | $$\\ $$ | $$| $$| $$| $$ | $$ \____ $$| $$_____/| $$ ');
console.log('| $$$$$$/ | $$ | $$ \ $$| $$| $$| $$| $$$$$$/ /$$$$$$$/| $$$$$$$| $$ ');
console.log(' \______/ |__/ |__/ \__/|__/|__/|__/ \______/ |_______/ \_______/|__/ ');
console.log('____________');
console.log('𝐊𝐢𝐥𝐥𝐔𝐬𝐞𝐫-𝐒𝐦𝐚𝐫𝐭𝐓𝐞𝐚𝐜𝐡 v1.0');
console.log('𝐁𝐲 𝐚𝐩𝐚𝐧𝐳𝐢𝐧𝐜');
console.log('如遇问题欢迎反馈');
// 要屏蔽的用户名列表,使用localStorage持久化存储Z
let blockedUsers = JSON.parse(localStorage.getItem('killUserSmartTeachBlockedUsers')) || ['默认用户'];
// 日志开关,默认关闭
let enableLogs = JSON.parse(localStorage.getItem('killUserSmartTeachEnableLogs')) === true;
// 自定义日志函数,根据开关状态决定是否输出
function log(...args) {
if (enableLogs) {
// 获取当前时间
const now = new Date();
const timeString = now.toLocaleTimeString('zh-CN', { hour12: false });
// 统一日志格式,添加时间戳和前缀
console.log(`[${timeString}] 🛡️ KillUser:`, ...args);
}
}
// 操作日志,用于记录用户操作
function logAction(action) {
if (enableLogs) {
const now = new Date();
const timeString = now.toLocaleTimeString('zh-CN', { hour12: false });
console.log(`[${timeString}] ✨ Action: ${action}`);
}
}
// 屏蔽日志,用于记录屏蔽操作
function logBlock(action, username, details = '') {
if (enableLogs) {
const now = new Date();
const timeString = now.toLocaleTimeString('zh-CN', { hour12: false });
console.log(`[${timeString}] 🔴 Block: ${action} - ${username} ${details}`);
}
}
log(`当前屏蔽用户列表: ${blockedUsers.join(', ')}`);
log(`日志输出: ${enableLogs ? '开启' : '关闭'}`);
// 保存屏蔽用户列表到localStorage
function saveBlockedUsers() {
localStorage.setItem('killUserSmartTeachBlockedUsers', JSON.stringify(blockedUsers));
log(`屏蔽用户列表已保存: ${blockedUsers.join(', ')}`);
}
// 保存日志开关状态到localStorage
function saveEnableLogs() {
localStorage.setItem('killUserSmartTeachEnableLogs', JSON.stringify(enableLogs));
log(`日志开关状态已保存: ${enableLogs ? '开启' : '关闭'}`);
}
// 在设置页面添加图形界面
function addSettingsUI() {
// 检查是否是设置页面
if (window.location.pathname !== '/settings') {
return;
}
console.log('在设置页面添加图形界面...');
// 创建UI容器
const uiContainer = document.createElement('div');
uiContainer.innerHTML = `
🔪 𝐊𝐢𝐥𝐥𝐔𝐬𝐞𝐫-𝐒𝐦𝐚𝐫𝐭𝐓𝐞𝐚𝐜𝐡 设置
高级设置:
控制台日志输出:
💡 提示: 保存设置后刷新页面生效
📝 支持的屏蔽类型: 帖子、月活榜单、在线榜单、管理员列表、通知、评论、@提及
🔧 作者: apanzinc | 版本: v1.0 | GitHub仓库
`;
// 添加样式
const style = document.createElement('style');
style.textContent = `
.killuser-ui {
margin: 20px 0;
padding: 20px 0;
background: transparent;
border-radius: 0;
box-shadow: none;
}
.killuser-ui h3 {
margin-top: 0;
color: #333;
}
.killuser-ui-input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
width: 200px;
}
.killuser-ui-add {
background: #28a745;
color: white;
border: none;
padding: 8px 15px;
border-radius: 4px;
cursor: pointer;
margin-left: 10px;
}
.killuser-ui-delete {
background: #dc3545;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
margin-left: 10px;
}
`;
document.head.appendChild(style);
// 尝试将UI放置在"关注标签"部分下方
const followTagsSection = document.querySelector('.item-fof-follow-tags');
if (followTagsSection) {
// 将UI插入到关注标签部分的下方
followTagsSection.insertAdjacentElement('afterend', uiContainer);
console.log('UI已添加到关注标签部分下方');
} else {
// 找不到关注标签部分,尝试其他容器
let container = document.querySelector('.container');
let containerFound = false;
// 如果找不到container,尝试其他可能的容器
if (!container) {
container = document.querySelector('#app');
if (container) {
console.log('找到app容器,将UI添加到app容器中');
containerFound = true;
}
} else {
containerFound = true;
console.log('找到container容器,将UI添加到container容器中');
}
// 如果还是找不到,使用body
if (!containerFound) {
container = document.body;
console.log('使用body作为容器,将UI添加到body中');
}
// 添加到页面底部
if (container) {
container.appendChild(uiContainer);
console.log('UI已添加到页面');
}
}
// 更新用户列表
updateBlockedUsersList();
// 添加事件监听
const addBtn = document.getElementById('killuser-add-btn');
if (addBtn) {
addBtn.addEventListener('click', addBlockedUser);
log('添加按钮事件监听已绑定');
} else {
log('未找到添加按钮');
}
// 添加日志开关按钮事件监听
const logsBtn = document.getElementById('killuser-logs-btn');
if (logsBtn) {
logsBtn.addEventListener('click', toggleLogs);
log('日志开关按钮事件监听已绑定');
} else {
log('未找到日志开关按钮');
}
// 切换日志开关状态
function toggleLogs() {
enableLogs = !enableLogs;
saveEnableLogs();
// 更新按钮样式和文本
const logsBtn = document.getElementById('killuser-logs-btn');
if (logsBtn) {
logsBtn.textContent = enableLogs ? '开启' : '关闭';
logsBtn.style.background = enableLogs ? '#28a745' : '#6c757d';
}
log(`日志输出已${enableLogs ? '开启' : '关闭'}`);
}
// 更新屏蔽用户列表
function updateBlockedUsersList() {
const listContainer = document.getElementById('killuser-blocked-list');
if (!listContainer) {
log('未找到用户列表容器');
return;
}
let html = '';
if (blockedUsers.length === 0) {
html = '(暂无屏蔽用户)
';
} else {
html = '';
blockedUsers.forEach((user, index) => {
html += `
${user}
`;
});
html += '
';
}
listContainer.innerHTML = html;
log('用户列表已更新');
// 添加删除按钮事件监听
document.querySelectorAll('.killuser-ui-delete').forEach(btn => {
btn.addEventListener('click', function() {
const index = parseInt(this.dataset.index);
removeBlockedUser(index);
});
});
}
// 添加屏蔽用户
function addBlockedUser() {
const input = document.getElementById('killuser-add-input');
if (!input) {
log('未找到输入框');
return;
}
const username = input.value.trim();
if (username && !blockedUsers.includes(username)) {
blockedUsers.push(username);
saveBlockedUsers();
updateBlockedUsersList();
input.value = '';
log(`已添加屏蔽用户: ${username}`);
}
}
// 删除屏蔽用户
function removeBlockedUser(index) {
const username = blockedUsers[index];
blockedUsers.splice(index, 1);
saveBlockedUsers();
updateBlockedUsersList();
log(`已删除屏蔽用户: ${username}`);
}
}
// 调用添加UI函数
setTimeout(addSettingsUI, 500);
// 监听页面URL变化,处理单页应用路由切换
let currentUrl = window.location.href;
setInterval(function() {
if (window.location.href !== currentUrl) {
currentUrl = window.location.href;
log(`检测到URL变化: ${currentUrl}`);
// 检查是否切换到设置页面
if (window.location.pathname === '/settings') {
log('切换到设置页面,重新添加UI');
// 移除已存在的UI,避免重复添加
const existingUI = document.querySelector('.killuser-ui');
if (existingUI) {
existingUI.remove();
log('已移除旧UI');
}
// 重新添加UI
addSettingsUI();
}
}
}, 500);
// 屏蔽用户帖子的函数
function blockUsers(isDynamic = false) {
let totalBlockedCount = 0;
if (!isDynamic) {
log('开始执行用户屏蔽操作...');
}
// 1. 处理帖子列表
const discussionItems = document.querySelectorAll('.DiscussionListItem-content');
let postBlockedCount = 0;
discussionItems.forEach(item => {
// 查找作者链接
const authorLink = item.querySelector('.DiscussionListItem-author');
if (authorLink) {
// 从链接中提取用户名
const authorHref = authorLink.getAttribute('href');
const username = authorHref.replace('/u/', '');
// 获取帖子标题
const titleElement = item.querySelector('.DiscussionListItem-title');
const title = titleElement ? titleElement.textContent.trim() : '未找到标题';
// 如果用户名在屏蔽列表中,隐藏该帖子
if (blockedUsers.includes(username)) {
item.style.display = 'none';
postBlockedCount++;
totalBlockedCount++;
if (!isDynamic) {
logBlock('帖子', username, `- "${title}"`);
}
}
}
});
// 2. 处理各种榜单(月活榜单 + 在线榜单 + 管理员列表)
const allWidgetItems = document.querySelectorAll('.Afrux-TopPostersWidget-users-item, .Afrux-OnlineUsersWidget-users-item, .Widget-users-item, .OnlineUsers-widget-item, .staff-members-flex, [class*="widget"] [class*="user"][class*="item"], [class*="staff"] [class*="member"]');
let widgetBlockedCount = 0;
allWidgetItems.forEach(item => {
// 方法1: 从用户名文本获取
let username = '';
// 尝试从多种可能的位置获取用户名
const userNameElement = item.querySelector('.Afrux-TopPostersWidget-users-item-name, .username, [class*="name"], [class*="username"], .staffmemberslink, .staff-members-details a, .staffmemberslink strong');
if (userNameElement) {
username = userNameElement.textContent.trim();
}
// 方法2: 从头像的alt属性或title属性获取
else {
const avatarElement = item.querySelector('img.Avatar');
if (avatarElement) {
// 从alt或title属性获取用户名
username = avatarElement.alt || avatarElement.title || avatarElement.getAttribute('aria-label') || '';
// 清理用户名(移除可能的空格和特殊字符)
username = username.trim();
}
}
if (username && blockedUsers.includes(username)) {
item.style.display = 'none';
widgetBlockedCount++;
totalBlockedCount++;
if (!isDynamic) {
logBlock('榜单用户', username);
}
}
});
// 3. 处理通知
const notifications = document.querySelectorAll('.Notification');
let notificationBlockedCount = 0;
notifications.forEach(item => {
// 获取用户名
const userNameElement = item.querySelector('.username');
if (userNameElement) {
const username = userNameElement.textContent.trim();
if (blockedUsers.includes(username)) {
item.style.display = 'none';
notificationBlockedCount++;
totalBlockedCount++;
if (!isDynamic) {
logBlock('通知', username);
}
}
}
});
// 4. 处理帖子详情页评论
const commentPosts = document.querySelectorAll('.CommentPost');
let commentBlockedCount = 0;
commentPosts.forEach(item => {
// 获取用户名
const userNameElement = item.querySelector('.PostUser-name .username');
if (userNameElement) {
const username = userNameElement.textContent.trim();
if (blockedUsers.includes(username)) {
item.style.display = 'none';
commentBlockedCount++;
totalBlockedCount++;
if (!isDynamic) {
logBlock('评论', username);
}
}
}
});
// 5. 处理帖子内容中的用户提及 (@用户名)
const postMentions = document.querySelectorAll('.PostMention');
let mentionBlockedCount = 0;
postMentions.forEach(item => {
// 获取提及的用户名
const username = item.textContent.trim();
if (blockedUsers.includes(username)) {
item.style.display = 'none';
mentionBlockedCount++;
totalBlockedCount++;
if (!isDynamic) {
logBlock('提及', username);
}
}
});
// 6. 处理"回复了此帖"部分
const repliedByElements = document.querySelectorAll('.Post-mentionedBy-summary');
let repliedByBlockedCount = 0;
repliedByElements.forEach(item => {
// 获取用户名
const userNameElement = item.querySelector('.username');
if (userNameElement) {
const username = userNameElement.textContent.trim();
if (blockedUsers.includes(username)) {
item.style.display = 'none';
repliedByBlockedCount++;
totalBlockedCount++;
if (!isDynamic) {
logBlock('回复提示', username);
}
}
}
});
// 7. 输出日志
if (isDynamic) {
// 动态执行,一行输出
log(`🔄 动态屏蔽完成: 帖子(${discussionItems.length}个)屏蔽${postBlockedCount}个, 榜单(${allWidgetItems.length}个)屏蔽${widgetBlockedCount}个, 通知(${notifications.length}条)屏蔽${notificationBlockedCount}个, 评论(${commentPosts.length}条)屏蔽${commentBlockedCount}个, 提及(${postMentions.length}个)屏蔽${mentionBlockedCount}个, 回复提示(${repliedByElements.length}个)屏蔽${repliedByBlockedCount}个, 总计${totalBlockedCount}项`);
} else {
// 初始执行,详细输出
log(`找到 ${discussionItems.length} 个帖子, ${allWidgetItems.length} 个榜单用户, ${notifications.length} 条通知, ${commentPosts.length} 条评论, ${postMentions.length} 个用户提及, ${repliedByElements.length} 个回复提示`);
log(`屏蔽操作完成,共屏蔽 ${totalBlockedCount} 项 (帖子: ${postBlockedCount} 个, 榜单用户: ${widgetBlockedCount} 个, 通知: ${notificationBlockedCount} 条, 评论: ${commentBlockedCount} 条, 提及: ${mentionBlockedCount} 个, 回复提示: ${repliedByBlockedCount} 个)`);
}
}
// 页面加载完成后执行一次
window.addEventListener('load', function() {
log('页面加载完成,执行初始屏蔽');
blockUsers();
});
// 监听页面动态内容变化(针对可能的AJAX加载)
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length > 0) {
blockUsers(true); // 传递参数表示是动态执行
}
});
});
// 观察目标节点
const targetNode = document.body;
const config = {
childList: true,
subtree: true
};
// 开始观察
observer.observe(targetNode, config);
log('已启动页面内容变化监听');
// 添加页面可见性监听,当用户切换回标签页时重新执行屏蔽
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'visible') {
log('页面重新可见,执行屏蔽检查');
blockUsers(true); // 使用动态执行模式
}
});
// 添加页面导航监听,处理浏览器前进后退和hash变化
window.addEventListener('popstate', function() {
log('检测到页面导航(前进/后退),执行屏蔽检查');
blockUsers(true);
});
// 添加hash变化监听,处理页面内导航
window.addEventListener('hashchange', function() {
log('检测到hash变化,执行屏蔽检查');
blockUsers(true);
});
// 监听页面焦点事件
window.addEventListener('focus', function() {
log('页面获得焦点,执行屏蔽检查');
blockUsers(true);
});
})();