338 lines
8.6 KiB
JavaScript
338 lines
8.6 KiB
JavaScript
import path from "node:path"
|
|
import fs from "node:fs"
|
|
|
|
Bot.adapter.push(new class OPQBotAdapter {
|
|
constructor() {
|
|
this.id = "QQ"
|
|
this.name = "OPQBot"
|
|
this.path = this.name
|
|
this.CommandId = {
|
|
FriendImage: 1,
|
|
GroupImage: 2,
|
|
FriendVoice: 26,
|
|
GroupVoice: 29,
|
|
}
|
|
}
|
|
|
|
sendApi(id, CgiCmd, CgiRequest) {
|
|
const ReqId = Math.round(Math.random()*10**16)
|
|
Bot[id].ws.sendMsg({ BotUin: String(id), CgiCmd, CgiRequest, ReqId })
|
|
return new Promise(resolve =>
|
|
Bot.once(ReqId, data => resolve(data)))
|
|
}
|
|
|
|
toStr(data) {
|
|
switch (typeof data) {
|
|
case "string":
|
|
return data
|
|
case "number":
|
|
return String(data)
|
|
case "object":
|
|
if (Buffer.isBuffer(data))
|
|
return Buffer.from(data, "utf8").toString()
|
|
else
|
|
return JSON.stringify(data)
|
|
}
|
|
return data
|
|
}
|
|
|
|
makeLog(msg) {
|
|
return this.toStr(msg).replace(/base64:\/\/.*?"/g, 'base64://..."')
|
|
}
|
|
|
|
async uploadFile(id, type, file) {
|
|
const opts = { CommandId: this.CommandId[type] }
|
|
|
|
if (file.match(/^base64:\/\//))
|
|
opts.Base64Buf = file.replace(/^base64:\/\//, "")
|
|
else if (file.match(/^https?:\/\//))
|
|
opts.FileUrl = file
|
|
else
|
|
opts.FilePath = file
|
|
|
|
return (await this.sendApi(id, "PicUp.DataUp", opts)).ResponseData
|
|
}
|
|
|
|
async sendMsg(send, upload, msg) {
|
|
if (!Array.isArray(msg))
|
|
msg = [msg]
|
|
const message = {
|
|
Content: "",
|
|
Images: [],
|
|
AtUinLists: [],
|
|
}
|
|
|
|
for (let i of msg) {
|
|
if (typeof i != "object")
|
|
i = { type: "text", text: i }
|
|
|
|
switch (i.type) {
|
|
case "text":
|
|
message.Content += i.text
|
|
break
|
|
case "image":
|
|
message.Images.push(await upload("Image", i.file))
|
|
break
|
|
case "record":
|
|
message.Voice = await upload("Voice", i.file)
|
|
break
|
|
case "at":
|
|
message.AtUinLists.push({ Uin: i.qq })
|
|
break
|
|
case "video":
|
|
case "file":
|
|
case "face":
|
|
case "reply":
|
|
continue
|
|
case "node":
|
|
await Bot.sendForwardMsg(msg => this.sendMsg(send, upload, msg), i.data)
|
|
continue
|
|
default:
|
|
message.Content += JSON.stringify(i)
|
|
}
|
|
}
|
|
|
|
return send(message)
|
|
}
|
|
|
|
sendFriendMsg(data, msg, event) {
|
|
logger.info(`${logger.blue(`[${data.self_id}]`)} 发送好友消息:[${data.user_id}] ${this.makeLog(msg)}`)
|
|
return this.sendMsg(
|
|
msg => this.sendApi(data.self_id,
|
|
"MessageSvc.PbSendMsg", {
|
|
ToUin: data.user_id,
|
|
ToType: 1,
|
|
...msg,
|
|
}),
|
|
(type, file) => this.uploadFile(data.self_id, `Friend${type}`, file),
|
|
msg
|
|
)
|
|
}
|
|
|
|
sendMemberMsg(data, msg, event) {
|
|
logger.info(`${logger.blue(`[${data.self_id}]`)} 发送群员消息:[${data.group_id}, ${data.user_id}] ${this.makeLog(msg)}`)
|
|
return this.sendMsg(
|
|
msg => this.sendApi(data.self_id,
|
|
"MessageSvc.PbSendMsg", {
|
|
ToUin: data.user_id,
|
|
GroupCode: data.group_id,
|
|
ToType: 3,
|
|
...msg,
|
|
}),
|
|
(type, file) => this.uploadFile(data.self_id, `Friend${type}`, file),
|
|
msg
|
|
)
|
|
}
|
|
|
|
sendGroupMsg(data, msg) {
|
|
logger.info(`${logger.blue(`[${data.self_id}]`)} 发送群消息:[${data.group_id}] ${this.makeLog(msg)}`)
|
|
let ReplyTo
|
|
if (data.message_id && data.seq && data.time)
|
|
ReplyTo = {
|
|
MsgSeq: data.seq,
|
|
MsgTime: data.time,
|
|
MsgUid: data.message_id,
|
|
}
|
|
|
|
return this.sendMsg(
|
|
msg => this.sendApi(data.self_id,
|
|
"MessageSvc.PbSendMsg", {
|
|
ToUin: data.group_id,
|
|
ToType: 2,
|
|
ReplyTo,
|
|
...msg,
|
|
}),
|
|
(type, file) => this.uploadFile(data.self_id, `Group${type}`, file),
|
|
msg
|
|
)
|
|
}
|
|
|
|
pickFriend(id, user_id) {
|
|
const i = {
|
|
...Bot[id].fl.get(user_id),
|
|
self_id: id,
|
|
bot: Bot[id],
|
|
user_id: user_id,
|
|
}
|
|
return {
|
|
...i,
|
|
sendMsg: msg => this.sendFriendMsg(i, msg),
|
|
}
|
|
}
|
|
|
|
pickMember(id, group_id, user_id) {
|
|
const i = {
|
|
...Bot[id].fl.get(user_id),
|
|
self_id: id,
|
|
bot: Bot[id],
|
|
user_id: user_id,
|
|
group_id: group_id,
|
|
}
|
|
return {
|
|
...this.pickFriend(id, user_id),
|
|
...i,
|
|
sendMsg: msg => this.sendMemberMsg(i, msg),
|
|
}
|
|
}
|
|
|
|
pickGroup(id, group_id) {
|
|
const i = {
|
|
...Bot[id].gl.get(group_id),
|
|
self_id: id,
|
|
bot: Bot[id],
|
|
group_id: group_id,
|
|
}
|
|
return {
|
|
...i,
|
|
sendMsg: msg => this.sendGroupMsg(i, msg),
|
|
pickMember: user_id => this.pickMember(id, group_id, user_id),
|
|
}
|
|
}
|
|
|
|
makeMessage(id, event) {
|
|
const data = {
|
|
event,
|
|
bot: Bot[id],
|
|
self_id: id,
|
|
post_type: "message",
|
|
message_id: event.MsgHead.MsgUid,
|
|
seq: event.MsgHead.MsgSeq,
|
|
time: event.MsgHead.MsgTime,
|
|
user_id: event.MsgHead.SenderUin,
|
|
sender: {
|
|
user_id: event.MsgHead.SenderUin,
|
|
nickname: event.MsgHead.SenderNick,
|
|
},
|
|
message: [],
|
|
raw_message: "",
|
|
}
|
|
|
|
if (event.MsgBody.AtUinLists)
|
|
for (const i of event.MsgBody.AtUinLists) {
|
|
data.message.push({
|
|
type: "at",
|
|
qq: i.Uin,
|
|
data: i,
|
|
})
|
|
data.raw_message += `[提及:${i.Uin}]`
|
|
}
|
|
|
|
if (event.MsgBody.Content) {
|
|
data.message.push({
|
|
type: "text",
|
|
text: event.MsgBody.Content,
|
|
})
|
|
data.raw_message += event.MsgBody.Content
|
|
}
|
|
|
|
if (event.MsgBody.Images)
|
|
for (const i of event.MsgBody.Images) {
|
|
data.message.push({
|
|
type: "image",
|
|
url: i.Url,
|
|
data: i,
|
|
})
|
|
data.raw_message += `[图片:${i.Url}]`
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
makeFriendMessage(id, data) {
|
|
if (!data.MsgBody) return
|
|
data = this.makeMessage(id, data)
|
|
data.message_type = "private"
|
|
|
|
logger.info(`${logger.blue(`[${data.self_id}]`)} 好友消息:[${data.sender.nickname}(${data.user_id})] ${data.raw_message}`)
|
|
Bot.em(`${data.post_type}.${data.message_type}`, data)
|
|
}
|
|
|
|
makeGroupMessage(id, data) {
|
|
if (!data.MsgBody) return
|
|
data = this.makeMessage(id, data)
|
|
data.message_type = "group"
|
|
data.sender.card = data.event.MsgHead.GroupInfo.GroupCard
|
|
data.group_id = data.event.MsgHead.GroupInfo.GroupCode
|
|
data.group_name = data.event.MsgHead.GroupInfo.GroupName
|
|
|
|
data.reply = msg => this.sendGroupMsg(data, msg)
|
|
logger.info(`${logger.blue(`[${data.self_id}]`)} 群消息:[${data.group_name}(${data.group_id}), ${data.sender.nickname}(${data.user_id})] ${data.raw_message}`)
|
|
Bot.em(`${data.post_type}.${data.message_type}`, data)
|
|
}
|
|
|
|
makeEvent(id, data) {
|
|
switch (data.EventName) {
|
|
case "ON_EVENT_FRIEND_NEW_MSG":
|
|
this.makeFriendMessage(id, data.EventData)
|
|
break
|
|
case "ON_EVENT_GROUP_NEW_MSG":
|
|
this.makeGroupMessage(id, data.EventData)
|
|
break
|
|
default:
|
|
logger.warn(`${logger.blue(`[${id}]`)} 未知事件:${logger.magenta(JSON.stringify(data))}`)
|
|
}
|
|
}
|
|
|
|
makeBot(id, ws) {
|
|
Bot[id] = {
|
|
adapter: this,
|
|
ws,
|
|
|
|
uin: id,
|
|
info: { id },
|
|
get nickname() { return this.info.nickname },
|
|
get avatar() { return `https://q1.qlogo.cn/g?b=qq&s=0&nk=${this.uin}` },
|
|
|
|
version: {
|
|
id: this.id,
|
|
name: this.name,
|
|
version: this.version,
|
|
},
|
|
stat: { start_time: Date.now()/1000 },
|
|
|
|
pickFriend: user_id => this.pickFriend(id, user_id),
|
|
get pickUser() { return this.pickFriend },
|
|
getFriendMap() { return this.fl },
|
|
fl: new Map,
|
|
|
|
pickMember: (group_id, user_id) => this.pickMember(id, group_id, user_id),
|
|
pickGroup: group_id => this.pickGroup(id, group_id),
|
|
getGroupMap() { return this.gl },
|
|
gl: new Map,
|
|
gml: new Map,
|
|
}
|
|
|
|
logger.mark(`${logger.blue(`[${id}]`)} ${this.name}(${this.id}) ${this.version} 已连接`)
|
|
Bot.em(`connect.${id}`, { self_id: id })
|
|
}
|
|
|
|
message(data, ws) {
|
|
try {
|
|
data = JSON.parse(data)
|
|
} catch (err) {
|
|
return logger.error(`解码数据失败:${logger.red(err)}`)
|
|
}
|
|
|
|
const id = data.CurrentQQ
|
|
if (id && data.CurrentPacket) {
|
|
if (Bot[id])
|
|
Bot[id].ws = ws
|
|
else
|
|
this.makeBot(id, ws)
|
|
|
|
this.makeEvent(id, data.CurrentPacket)
|
|
} else if (data.ReqId) {
|
|
Bot.emit(data.ReqId, data)
|
|
} else {
|
|
logger.warn(`${logger.blue(`[${id}]`)} 未知消息:${logger.magenta(JSON.stringify(data))}`)
|
|
}
|
|
}
|
|
|
|
load() {
|
|
if (!Array.isArray(Bot.wsf[this.path]))
|
|
Bot.wsf[this.path] = []
|
|
Bot.wsf[this.path].push((ws, ...args) =>
|
|
ws.on("message", data => this.message(data, ws, ...args))
|
|
)
|
|
}
|
|
}) |