// 聊天框的CSS选择器
const chatBoxSelector = 'textarea.w-full.p-0';
// 发送按钮的CSS选择器
const sendButtonSelector = 'button.absolute.p-1';
// 正在输入动效(取代发送按钮)的CSS选择器
const replyNotReadySelector = 'div.text-2xl';
// 聊天回答的CSS选择器
const chatReplySelector = 'div.markdown';
// 用户自身的虎绿林uid
const hu60MyUid = 19346; // 改成自己的uid
// 用户的虎绿林sid
const hu60Sid = '4JfOlTT3iHw58i1ITtpS0okksAAA';
// 带sid的虎绿林URL
const hu60BaseUrl = 'https://hu60.cn/q.php/' + hu60Sid + '/';
/////////////////////////////////////////////////////////////
// 发送聊天信息
function sendText(text) {
let chatBox = document.querySelector(chatBoxSelector);
let sendButton = document.querySelector(sendButtonSelector);
chatBox.value = text;
sendButton.click();
}
// 读取响应
function readReply() {
let reply = Array.from(document.querySelectorAll(chatReplySelector)).at(-1);
let lines = [];
if (!reply.childNodes) {
// 错误信息
return reply.innerText;
}
reply.childNodes.forEach(x => {
if (x.tagName == 'PRE') { // 代码
lines.push("\n```\n" + x.querySelector('code').innerText + "\n```\n");
} else { // 正文
lines.push(x.innerText);
}
});
return lines.join("\n\n");
}
// 判断响应是否结束
function isFinished() {
return document.querySelector(replyNotReadySelector) == null;
}
// 读取@消息
async function readAtInfo() {
let response = await fetch(hu60BaseUrl + 'msg.index.@.no.json?_origin=*&_content=json');
return await response.json();
}
// 读取帖子内容
async function readTopicContent(path) {
let url = hu60BaseUrl + path.replace('{$BID}', 'json').replace('?', '?_origin=*&_content=text&pageSize=1&');
let response = await fetch(url);
return await response.json();
}
// 回复帖子
async function replyTopic(uid, replyText, topicObject) {
let content = "<!md>\n@#" + uid + "," + replyText;
let url = null;
if (topicObject.tMeta) { // 帖子
url = 'bbs.newreply.'+encodeURIComponent(topicObject.tContents[0].topic_id)+'.json';
} else { // 聊天室
url = 'addin.chat.'+encodeURIComponent(topicObject.chatRomName)+'.json';
}
let formData = new FormData();
formData.append('content', content);
formData.append('token', topicObject.token);
formData.append('go', '1');
let response = await fetch(hu60BaseUrl + url + '?_origin=*', {
body: formData,
method: "post",
redirect: "manual" // 不自动重定向
});
return response;
}
// 休眠指定的毫秒数
// 用法:await sleep(1000)
const sleep = ms => new Promise(r => setTimeout(r, ms));
// 回复@信息
async function replyAtInfo(info) {
try {
let uid = info.byuid;
let url = info.content[0].url;
let floor = url.split('#')[1];
// 防止自己和自己对话
if (uid == hu60MyUid || uid < 1) {
return;
}
console.log(info);
let topicObject = await readTopicContent(url);
let text = null;
if (topicObject.tContents) {
text = topicObject.tContents[0].content;
} else {
text = topicObject.chatList[0].content;
}
sendText(text);
do {
await sleep(500);
} while (!isFinished());
let replyText = readReply();
let response = await replyTopic(uid, replyText, topicObject);
console.log(response);
} catch (ex) {
console.error(ex);
}
}
// 运行机器人
async function run() {
console.log('虎绿林ChatGPT机器人已启动');
while (true) {
try {
// 浏览器用户可能直接输入了问题,等待回答完成
if (!isFinished()) {
do {
await sleep(500);
} while (!isFinished());
}
let atInfo = await readAtInfo();
console.log(new Date(), atInfo);
for (let i=0; i<atInfo.msgList.length; i++) {
await replyAtInfo(atInfo.msgList[i]);
}
await sleep(1000);
} catch (ex) {
console.error(ex);
}
}
}
run();
一加8Pro