// ==UserScript==
// @name ZhChat增强脚本
// @namespace http://tampermonkey.net/
// @version 3.2.9
// @description 增强功能:鼠标中键oldnick(已消抖)、自定义邀请、过滤rule,自动更新(提醒)、lookup、lookuplast(脚本)、/zhelp(更新显示命令帮助)
// @author UbisoComes (GreenDebug)
// @match https://chat.zhangsoft.cf/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=zhangsoft.cf
// @license MIT
// @run-at document-end
// @grant none
// ==/UserScript==
window._script_version = {
ver: '3.2.9',
update_note: `更新内容:鼠标中键oldnick(已消抖)、自定义邀请、过滤rule、自动更新(提醒)、/lookup功能(脚本)、/lookuplast (脚本)、/zhelp(更新显示命令帮助)、/addshortcmd /delshortcmd(快捷命令)
优化:
1.修复\`hook\`的问题
2.优化判断逻辑,防止 多判、漏判的问题
3.修复版本号显示时机
4.修复缓存问题,防止更新提醒失效
5.修复\`lookup\`的问题
6.修复\`addshortcmd\`命令的hook
7.修复\`fastcmd\`报错修改为空数组`
};
(function () {
/**
* 储存
*/
const local = {
set: (key, value) => localStorage.setItem(key, value),
remove: (key) => localStorage.removeItem(key),
get: (key) => {
let res = localStorage.getItem(key);
return res != null ? res : undefined;
},
exist: (key) => localStorage.getItem(key) != undefined,
};
const json = JSON;
/**
* 提示
*/
var is_trip_update = false, is_show_ver = false;
const doc = window.document;
const $_ = (q) => doc.querySelectorAll(q);
const $ = (d) => doc.querySelector(d);
/**
* 翻译
*/
var tr = {
nick: "用户名", trip: "识别码", utype: "用户类型",
hash: "hash", level: "等级", userid: "用户id",
channel: "频道", client: "客户端", isme: "是我吗"
};
/**
* 等级翻译
*/
var leveltr = { "user": "普通用户", "trusted": "信任用户", "mod": "管理员", "channelOwner": "房主" };
function info(t) {
COMMANDS.info({ cmd: 'info', text: t });
}
function warn(e) {
COMMANDS.warn({ cmd: 'warn', text: e });
}
/**
* 方便lookup、lookuplast
*/
window.zhcUsers = [];
/**
* 最后离开的用户
*/
window.lastLeave = false;
/**
* 数组去重
* @param {Array} _array
* @returns
*/
function trimSpace(_array) {
var array = _array;
for (var i = 0; i < array.length; i++) {
//这里为过滤的值
if (array[i] == " " || array[i] == null || typeof (array[i]) == "undefined" || array[i] == ' ' || array[i] == '') {
array.splice(i, 1);
i = i - 1;
}
}
return array;
}
/**
* 解除控制台限制
* @returns
*/
window.fuckconsole = function () {
var iframeid = parseInt(Math.random() * 1000);
pushMessage({ cmd: 'chat', text: `<iframe style='display:none;' id="${iframeid}"></iframe>` }, null, true);
return document.getElementById(iframeid).contentWindow.console;
};
window.msg = (e) => send({ cmd: 'chat', text: e, head: localStorageGet('head') || '' });
window._welcome = () => {
//直接扣client.js里面的 (
var hiyo = 'hi y'
var max = Math.round(Math.random() * 20);
for (var i = 0; i < max; i++) { // @ee 你想累死我啊
hiyo += 'o'; // ee:(被打
}
const welcomes = `${hiyo}|awa!|uwu!|来了老弟~`.split('|');
let txt = welcomes[Math.round(Math.random() * (welcomes.length - 1))];
return txt;
};
/**
* 格式化用户信息
* @param {String} user
* @returns
*/
function UserStr(user) {
//替换key
let new_user = Object.keys(user).reduce((newData, key) => {
let newKey = tr[key] || key;
newData[newKey] = '`' +
(s => {
//如果是true or false
if (typeof (s) == 'boolean') {
s = ({ 'true': '是', 'false': '否' })[s.toString()];
}
//如果包含mod等级字眼
if (Object.keys(leveltr).includes(s)) {
s = leveltr[s];
}
if (s == '' || s == undefined || s == null)
s = '空';
return s;
})(user[key]) + '`';
return newData;
}, {});
return JSON.stringify(new_user, null, 2).replaceAll('"', '').replaceAll('{', '').replaceAll('}', '');//直接格式化替换json
}
/**
* enum
*/
const Enum = {
skip: (arr, i) => {
let array = [];
for (let index = i; index < arr.length; index++) {
array.push(arr[index]);
}
return array;
}
};
var is_oldnick_ing = false;
/**
* 快捷命令
*/
window.fastcmd = [];
function isInfastcmd(ee) {
return fastcmd.find(c => c.name == ee) != undefined;
}
function getfastcmdValue(ee) {
return fastcmd.find(c => c.name == ee);
}
function savefastcmd() {
try {
local.set('fastcmd', json.stringify(fastcmd));
}
catch {
local.set('fastcmd', json.stringify([]));
}
}
function loadfastcmd() {
try {
fastcmd = json.parse(local.get('fastcmd')) || [];
}
catch {
fastcmd = [];
}
}
function addfastcmd(ee, value) {
if (!isInfastcmd(ee)) {
if (isInfastcmd(value))
return { success: false, msg: `不允许添加命令的值为:\`${value}\`,强制添加将导致递归` };
fastcmd.push({ name: ee, val: value });
savefastcmd();
return { success: true, msg: '添加成功' };
}
else return { success: false, msg: `添加失败,快捷命令:\`${ee}\` 已存在` };
}
function removefastcmd(ee) {
if (isInfastcmd(ee)) {
fastcmd.splice(fastcmd.findIndex(s => s.name == ee), 1);
savefastcmd();
return { success: true, msg: '移除成功' };
} else return { success: false, msg: `快捷命令:\`${ee}\` 不存在` };
}
window._isincmd = isInfastcmd;
/**
* 脚本命令
*/
window.Script_Command = {
zhelp: {
help: '帮助',
func: (e) => {
let keys = Object.keys(Script_Command);
if (e.length <= 0) info(`|命令列表:|\n|--|\n|${keys.join(',')}|\n要查看指定命令的帮助信息,请发送:\`/zhelp <command>\``);
else {
let cmd = keys.find(k => k == e.join(''));
if (cmd != undefined) info(`## ${cmd} 命令的帮助:\n|名称:|${cmd}|||\n|--|--|--|--|\n|帮助:|${Script_Command[cmd].help}|||\n|用法:|${Script_Command[cmd].use || '无'}|||`);
else warn('`help` 找不到命令');
}
},
use: '/zhelp <command> 或 /zhelp'
},
lookup: {
help: '查看某位用户',
func: (e) => {
let nick = e.join();
let user = zhcUsers.find(u => u.nick == nick);
if (user != undefined) info(`# ${user.nick} 的信息:\r\n` + UserStr(user));
else warn('`lookup` 找不到用户');
},
use: '/lookup <呢称>'
},
lookuplast: {
help: '查看最后离开的用户信息',
func: (e) => {
if (lastLeave != undefined && lastLeave != false) {
info('# 最后离开用户的信息:\r\n' + UserStr(lastLeave));
} else warn('最后离开的用户无记录');
},
use: '/lookuplast'
},
ver: {
help: '显示当前`zhc增强脚本`的版本号和更新内容',
func: (e) => {
info(`当前版本号:${_script_version.ver}
更新内容:${_script_version.update_note}`);
}, use: '/ver'
},
welcome: {
help: '显示一条一条欢迎信息',
func: (e) => msg(_welcome()),
use: '/welcome'
},
addshortcmd: {
help: '添加一条快捷命令',
use: '/addshortcmd <短的新命令> <命令>',
func: (e) => {
if (e.length < 2) return warn('缺少命令参数,请使用`/zhelp addshortcmd` 查看帮助');
let key = e[0];
let val = e[1];
let res = addfastcmd(key, val);
(res.success ? info : warn)(res.msg);
}
},
delshortcmd: {
help: '移除一条快捷命令',
use: '/delshortcmd <短的命令>',
func: (e) => {
if (e.length < 1) return warn('缺少命令参数,请使用`/zhelp delshortcmd` 查看帮助');
let res = removefastcmd(e[0]);
(res.success ? info : warn)(res.msg);
}
}
};
/**
* 侧边栏ui
*/
const SideBarUI = {
add: (element) => {
let side = $('#sidebar-content');
side.insertBefore(element, side.children[1]);
},
remove: (filther) => {
let side = $('#sidebar-content');
for (let i in side.children) {
let item = side.children[i];
if (filther(item)) side.removeChild(item);
}
}
};
/**
* 判断命令
* @param {String} c
* @returns
*/
function isCommand(c) {
var keys = Object.keys(Script_Command);
for (let p in keys) {
let item = keys[p];
if (item == c) return { success: true, obj: (e) => Script_Command[item].func(trimSpace(e)) };
if (isInfastcmd(c)) {
let val = getfastcmdValue(c).val;
return { success: true, obj: keys.includes(val) ? Script_Command[val].func : (e) => msg(`/${val}${e.length <= 0 ? '' : ' ' + e.join(' ')}`) };
}
}
return { success: false };
}
/**
* 处理脚本的命令
* @param {String} text
*/
function handleScriptCommand(e) {
if (e.cmd != "chat") return false;
if (!e.text.startsWith('/')) return false;
let t = e.text.slice(1).split(' ');
let f = (Enum.skip(t, 1));
let res = isCommand(t[0]);
if (res.success) {
res.obj(f);
return true;
}
return false;
}
/**
* 比较版本号
* @param {String} ver1
* @param {String} ver2
* @returns {Number}
*/
function compareVersion(ver1, ver2) {
const v1 = ver1.split('.').map(Number);
const v2 = ver2.split('.').map(Number);
const len = Math.max(v1.length, v2.length);
for (let i = 0; i < len; i++) {
const num1 = v1[i] || 0;
const num2 = v2[i] || 0;
if (num1 < num2) {
return -1;
} else if (num1 > num2) {
return 1;
}
}
return 0;
}
/**
* 检测更新
*
*/
function update_tip() {
//注意:此脚本用于更新,里面只包含版本号(其他的代码是无用的,为了让greasyfork不删除脚本
//脚本路径:https://gf.qytechs.cn/zh-CN/scripts/462606-%E7%9F%A5%E4%B9%8E-%E7%99%BE%E5%BA%A6%E5%8E%BB%E9%99%A4cookie
if (!is_trip_update) { is_trip_update = true; } else return;
var script = document.createElement("script");
script.src =
"https://gf.qytechs.cn/scripts/462606-%E7%9F%A5%E4%B9%8E-%E7%99%BE%E5%BA%A6%E5%8E%BB%E9%99%A4cookie" +
"/code/%E7%9F%A5%E4%B9%8E%E3%80%81%E7%99%BE%E5%BA%A6%E5%8E%BB%E9%99%A4cookie.user.js?cache=" + parseInt(Math.random() * 114514);
script.onload = () => {
if (compareVersion(_script_version.ver, gf_script_version.last_ver) < 0) {
info(`当前zhc增强脚本版本有更新! 请及时更新。
当前版本: ${_script_version.ver} 新版本: ${gf_script_version.last_ver}
新版本更新内容:${gf_script_version.last_note || '无'}`);
}
};
document.head.appendChild(script);
}
/**
* 鼠标中键oldnick
*/
function nick_oldnick() {
$('#sidebar-content').addEventListener('mousedown', (e) => {
if (e.button === 1) { // 检测是否为鼠标中键触发的事件
e.preventDefault();
}
[...$('#users').children].map(s => s.children[0]).forEach(q =>
q.addEventListener('mousedown', (e) => {
if (e.button == 1 && !is_oldnick_ing) {
send({ cmd: 'oldnick', nick: q.textContent });
is_oldnick_ing = true;
}
e.preventDefault();
}));
});
}
function version(p = false) {
if (!is_show_ver) { is_show_ver = true; } else return;//判断是否提醒过一次了
COMMANDS.info({
cmd: 'info', text: `zhchat增强脚本已启动,版本:v${_script_version.ver}
${_script_version.update_note}`
});
}
function initUI() {
nick_oldnick();//鼠标中键oldnick
}
function ChatLoaded() {
version();//版本
try {
update_tip();//更新提示
} catch { }
}
function init() {
/************** 初始化ui **************/
try {
initUI();//初始化ui
loadfastcmd();//从储存中加载fastcmd列表
window._console = fuckconsole();//解除控制台限制
window._info = info;
window._warn = warn;
}
catch { }
/**********************************/
/************** 版本号显示、rule拦截 ****************/
setTimeout(() => {
let _info = COMMANDS.info;
COMMANDS.info = (e) => {
e.nick = '*';
if (e.text.indexOf("曾用名") != -1) {
is_oldnick_ing = false;
}
if (e.type == "invite" && e.text.includes('\\rule')) {
e.text = e.text.replace(/\\rule/g, "【rule】")
_info({ cmd: 'info', text: 'rule已被拦截' })
}
_info(e);
};
}, 1000);
/************** lookup、lookuplast ****************/
setTimeout(() => {
let _onlineSet = COMMANDS['onlineSet'],
_onlineAdd = COMMANDS['onlineAdd'],
_onlineRemove = COMMANDS['onlineRemove'],
_changeNick = COMMANDS['changeNick'];
COMMANDS['onlineSet'] = (e) => {
_onlineSet(e);
ChatLoaded();
zhcUsers = e.users || [];
};
COMMANDS['onlineAdd'] = (e) => {
_onlineAdd(e);
delete e.cmd;
zhcUsers.push(e);
};
COMMANDS['onlineRemove'] = (e) => {
_onlineRemove(e);
delete e.cmd;
lastLeave = zhcUsers.find(u => u.nick == e.nick);
zhcUsers = zhcUsers.filter(u => u.nick != e.nick);
};
COMMANDS['changeNick'] = (e) => {
_changeNick(e);
zhcUsers.map(s => {
if (s.nick == e.nick) {
s.nick = e.text;
}
return s;
});
};
}, 1000);
/************** 自定义邀请 ****************/
setTimeout(() => {
userInvite = function (nick) {
var gotoChannel = prompt("设置一个去的频道(按取消随机)");
if (gotoChannel != undefined && gotoChannel.indexOf("\\rule") != -1)
return pushMessage({ nick: "!", text: "你干嘛,哈哈哎哟" });
send(gotoChannel ? { cmd: 'invite', nick: nick, to: gotoChannel } : { cmd: 'invite', nick: nick });
}
}, 1000);
/************** 捕获脚本命令 ****************/
setTimeout(() => {
var _send = send;
send = (e) => {
if (!handleScriptCommand(e)) _send(e);
};
}, 1000);
/******************************************/
}
init();
})();