// ==UserScript==
// @name [MWI] WebSocket 调试工具
// @namespace http://tampermonkey.net/
// @version 1.0.1
// @description 显示 WebSocket 收发的 JSON 数据,并支持手动发包和屏蔽指定类型
// @author XIxixi297
// @license MIT
// @match https://www.milkywayidle.com/*
// @match https://test.milkywayidle.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
if (window.__wsLoggerInstalled) return;
window.__wsLoggerInstalled = true;
// 全局状态
const wsLogger = {
instances: new Set(),
currentWS: null,
blockedTypes: new Set(),
STORAGE_KEY: 'ws_blocked_types'
};
// 初始化屏蔽列表
try {
const stored = localStorage.getItem(wsLogger.STORAGE_KEY);
if (stored) wsLogger.blockedTypes = new Set(JSON.parse(stored));
} catch (e) {}
function saveBlockedTypes() {
try {
localStorage.setItem(wsLogger.STORAGE_KEY, JSON.stringify([...wsLogger.blockedTypes]));
} catch (e) {}
}
// 消息日志记录
function logMessage(data, direction) {
try {
const parsed = typeof data === 'string' ? JSON.parse(data) : data;
const msgType = parsed.type || '未知类型';
if (!wsLogger.blockedTypes.has(msgType)) {
const color = direction === 'send' ? '#03A9F4' : '#4CAF50';
const arrow = direction === 'send' ? '→' : '←';
console.groupCollapsed(`%c${arrow} ${msgType}`, `color: ${color}; font-weight: bold;`);
console.log(parsed);
console.groupEnd();
}
} catch (e) {
const color = direction === 'send' ? '#03A9F4' : '#4CAF50';
const arrow = direction === 'send' ? '→' : '←';
console.log(`%c${arrow} 非JSON:`, `color: ${color};`, data);
}
}
// WebSocket劫持
const OriginalWebSocket = window.WebSocket;
window.WebSocket = function(url, protocols) {
const ws = new OriginalWebSocket(url, protocols);
// 添加到实例集合
wsLogger.instances.add(ws);
wsLogger.currentWS = ws;
// Hook send 方法
const originalSend = ws.send;
ws.send = function(data) {
logMessage(data, 'send');
return originalSend.apply(this, arguments);
};
// 监听消息
ws.addEventListener('message', (event) => {
logMessage(event.data, 'receive');
});
ws.addEventListener('open', () => {
console.info('%cWebSocket 已连接: ' + url, 'color: gray;');
});
ws.addEventListener('close', () => {
console.warn('%cWebSocket 已断开', 'color: orange;');
wsLogger.instances.delete(ws);
if (wsLogger.currentWS === ws) {
const remaining = [...wsLogger.instances];
wsLogger.currentWS = remaining[remaining.length - 1] || null;
}
});
return ws;
};
// 保持原型链
Object.setPrototypeOf(window.WebSocket, OriginalWebSocket);
window.WebSocket.prototype = OriginalWebSocket.prototype;
// 工具函数
window.sendWS = function(data) {
if (!wsLogger.currentWS || wsLogger.currentWS.readyState !== WebSocket.OPEN) {
console.error('没有可用的WebSocket连接');
return false;
}
const jsonData = typeof data === 'string' ? data : JSON.stringify(data);
wsLogger.currentWS.send(jsonData);
console.log('%c✅ 手动发送:', 'color: #FF9800; font-weight: bold;', data);
return true;
};
window.listWS = function() {
console.log('%cWebSocket 连接列表:', 'color: #9C27B0; font-weight: bold;');
[...wsLogger.instances].forEach((ws, index) => {
const status = ws.readyState === WebSocket.OPEN ? '✅' : '❌';
console.log(`[${index}] ${ws.url} ${status}`);
});
};
window.blockType = function(type) {
if (typeof type === 'string') {
wsLogger.blockedTypes.add(type);
} else if (Array.isArray(type)) {
type.forEach(t => wsLogger.blockedTypes.add(t));
}
saveBlockedTypes();
console.log('%c🚫 已屏蔽:', 'color: #F44336; font-weight: bold;', type);
};
window.unblockType = function(type) {
if (typeof type === 'string') {
wsLogger.blockedTypes.delete(type);
} else if (Array.isArray(type)) {
type.forEach(t => wsLogger.blockedTypes.delete(t));
}
saveBlockedTypes();
console.log('%c✅ 已取消屏蔽:', 'color: #4CAF50; font-weight: bold;', type);
};
window.listBlocked = function() {
if (wsLogger.blockedTypes.size === 0) {
console.log('%c无屏蔽类型', 'color: #607D8B;');
} else {
console.log('%c屏蔽列表:', 'color: #F44336; font-weight: bold;', [...wsLogger.blockedTypes]);
}
};
window.clearBlocked = function() {
const count = wsLogger.blockedTypes.size;
wsLogger.blockedTypes.clear();
saveBlockedTypes();
console.log(`%c✅ 已清空 ${count} 个屏蔽类型`, 'color: #4CAF50; font-weight: bold;');
};
// 启动提示
console.info('%c[MWI] WebSocket监听器已启用', 'color: purple; font-weight: bold;');
if (wsLogger.blockedTypes.size > 0) {
console.info(`%c已加载 ${wsLogger.blockedTypes.size} 个屏蔽类型:`, 'color: #FF9800; font-weight: bold;', [...wsLogger.blockedTypes]);
}
console.info('%c使用方法:', 'color: #2196F3; font-weight: bold;');
console.info('%c sendWS(data) - 发送消息到当前WebSocket', 'color: #2196F3;');
console.info('%c blockType(type) - 屏蔽指定类型消息 (支持字符串或数组)', 'color: #F44336;');
console.info('%c unblockType(type) - 取消屏蔽指定类型', 'color: #4CAF50;');
console.info('%c listBlocked() - 查看当前屏蔽的消息类型', 'color: #607D8B;');
console.info('%c clearBlocked() - 清空所有屏蔽类型', 'color: #607D8B;');
console.info('%c示例: blockType(["chat_message_received", "ping"]) - 屏蔽多个类型', 'color: #9E9E9E;');
})();