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))
 | 
						|
    )
 | 
						|
  }
 | 
						|
}) |