Compare commits

..

3 Commits

Author SHA1 Message Date
linyuchen
51602b987e fix: ws 没有上报群文件上传事件 2024-04-08 00:21:24 +08:00
linyuchen
b501af6e0e feat: 骰子魔法表情 & 猜拳魔法表情 2024-04-07 18:51:26 +08:00
linyuchen
81821e74d8 fix: 手动频繁切换聊天窗口时导致旧的窗口接收不到消息 2024-04-07 17:37:52 +08:00
9 changed files with 506 additions and 364 deletions

View File

@@ -1,10 +1,10 @@
{
"manifest_version": 4,
"type": "extension",
"name": "LLOneBot v3.21.0",
"name": "LLOneBot v3.22.0",
"slug": "LLOneBot",
"description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发, 不支持商店在线更新",
"version": "3.21.0",
"version": "3.22.0",
"icon": "./icon.jpg",
"authors": [
{

View File

@@ -1,6 +1,7 @@
import {
AtType,
ElementType,
FaceType,
PicType,
SendArkElement,
SendFaceElement,
@@ -18,6 +19,7 @@ import {calculateFileMD5, isGIF} from "../common/utils/file";
import {log} from "../common/utils/log";
import {defaultVideoThumb, getVideoInfo} from "../common/utils/video";
import {encodeSilk} from "../common/utils/audio";
import {isNull} from "../common/utils";
export class SendMsgElementConstructor {
@@ -237,7 +239,52 @@ export class SendMsgElementConstructor {
elementId: "",
faceElement: {
faceIndex: faceId,
faceType: 1
faceType: FaceType.normal
}
}
}
static dice(resultId: number|null): SendFaceElement{
// 实际测试并不能控制结果
// 随机1到6
if (isNull(resultId)) resultId = Math.floor(Math.random() * 6) + 1;
return {
elementType: ElementType.FACE,
elementId: "",
faceElement: {
faceIndex: 358,
faceType: FaceType.dice,
"faceText": "[骰子]",
"packId": "1",
"stickerId": "33",
"sourceType": 1,
"stickerType": 2,
resultId: resultId.toString(),
"surpriseId": "",
// "randomType": 1,
}
}
}
// 猜拳(石头剪刀布)表情
static rps(resultId: number | null): SendFaceElement{
// 实际测试并不能控制结果
if (isNull(resultId)) resultId = Math.floor(Math.random() * 3) + 1;
return {
elementType: ElementType.FACE,
elementId: "",
faceElement: {
"faceIndex": 359,
"faceText": "[包剪锤]",
"faceType": 3,
"packId": "1",
"stickerId": "34",
"sourceType": 1,
"stickerType": 2,
"resultId": resultId.toString(),
"surpriseId": "",
// "randomType": 1,
}
}
}

View File

@@ -1,8 +1,8 @@
import {BrowserWindow} from 'electron';
import {NTQQApiClass} from "./ntcall";
import {NTQQApiClass, NTQQApiMethod} from "./ntcall";
import {NTQQMsgApi, sendMessagePool} from "./api/msg"
import {ChatType, Group, GroupMember, GroupMemberRole, RawMessage, User} from "./types";
import {friends, getGroupMember, groups, selfInfo, tempGroupCodeMap, uidMaps} from "../common/data";
import {friends, getFriend, getGroupMember, groups, selfInfo, tempGroupCodeMap, uidMaps} from "../common/data";
import {OB11GroupDecreaseEvent} from "../onebot11/event/notice/OB11GroupDecreaseEvent";
import {v4 as uuidv4} from "uuid"
import {postOB11Event} from "../onebot11/server/postOB11Event";
@@ -11,7 +11,7 @@ import fs from "fs";
import {dbUtil} from "../common/db";
import {NTQQGroupApi} from "./api/group";
import {log} from "../common/utils/log";
import {sleep} from "../common/utils/helper";
import {isNumeric, sleep} from "../common/utils/helper";
import {OB11Constructor} from "../onebot11/constructor";
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
@@ -61,6 +61,12 @@ let receiveHooks: Array<{
id: string
}> = []
let callHooks: Array<{
method: NTQQApiMethod[],
hookFunc: ((callParams: unknown[]) => void | Promise<void>)
}> = []
export function hookNTQQApiReceive(window: BrowserWindow) {
const originalSend = window.webContents.send;
const patchSend = (channel: string, ...args: NTQQApiReturnData) => {
@@ -137,6 +143,27 @@ export function hookNTQQApiCall(window: BrowserWindow) {
HOOK_LOG && log("call NTQQ api", thisArg, args);
} catch (e) {
}
try {
const _args: unknown[] = args[3][1];
const cmdName: NTQQApiMethod = _args[0] as NTQQApiMethod;
const callParams = _args.slice(1);
callHooks.forEach(hook => {
if (hook.method.includes(cmdName)) {
new Promise((resolve, reject) => {
try {
let _ = hook.hookFunc(callParams)
if (hook.hookFunc.constructor.name === "AsyncFunction") {
(_ as Promise<void>).then()
}
} catch (e) {
log("hook call error", e, _args)
}
}).then()
}
})
} catch (e) {
}
}
return target.apply(thisArg, args);
@@ -187,6 +214,16 @@ export function registerReceiveHook<PayloadType>(method: ReceiveCmd | ReceiveCmd
return id;
}
export function registerCallHook(method: NTQQApiMethod | NTQQApiMethod[], hookFunc: (callParams: unknown[]) => void | Promise<void>): void {
if (!Array.isArray(method)) {
method = [method]
}
callHooks.push({
method,
hookFunc
})
}
export function removeReceiveHook(id: string) {
const index = receiveHooks.findIndex(h => h.id === id)
receiveHooks.splice(index, 1);
@@ -454,3 +491,23 @@ registerReceiveHook<{
}
}
})
registerCallHook(NTQQApiMethod.DELETE_ACTIVE_CHAT, async (payload) => {
const peerUid = payload[0] as string;
log("激活的聊天窗口被删除,准备重新激活", peerUid);
let chatType = ChatType.friend;
if (isNumeric(peerUid)) {
chatType = ChatType.group;
}
else{
// 检查是否好友
if (!(await getFriend(peerUid))){
chatType = ChatType.temp;
}
}
const peer = {peerUid, chatType}
await sleep(1000);
NTQQMsgApi.activateChat(peer).then((r) => {
log("重新激活聊天窗口", peer, {result: r.result, errMsg: r.errMsg})
});
})

View File

@@ -26,6 +26,7 @@ export enum NTQQApiMethod {
ACTIVE_CHAT_HISTORY = "nodeIKernelMsgService/getMsgsIncludeSelfAndAddActiveChat", // 激活聊天窗口,有时候必须这样才能收到消息, 并返回历史消息
HISTORY_MSG = "nodeIKernelMsgService/getMsgsIncludeSelf",
GET_MULTI_MSG = "nodeIKernelMsgService/getMultiMsg",
DELETE_ACTIVE_CHAT = "nodeIKernelMsgService/deleteActiveChatByUid",
LIKE_FRIEND = "nodeIKernelProfileLikeService/setBuddyProfileLike",
SELF_INFO = "fetchAuthData",

View File

@@ -212,9 +212,22 @@ export interface GrayTipElement {
}
}
export enum FaceType {
normal=1, // 小黄脸
dice=3 // 骰子
}
export interface FaceElement {
faceIndex: number,
faceType: 1
faceType: FaceType,
faceText?: string,
packId?: string,
stickerId?: string,
sourceType?: number,
stickerType?: number,
resultId?: string,
surpriseId?: string,
randomType?: number
}
export interface MarketFaceElement {

View File

@@ -224,6 +224,14 @@ export async function createSendElements(messageData: OB11MessageData[], target:
}
}
break;
case OB11MessageDataType.dice:{
const resultId = sendMsg.data?.result
sendElements.push(SendMsgElementConstructor.dice(resultId));
}break;
case OB11MessageDataType.RPS:{
const resultId = sendMsg.data?.result
sendElements.push(SendMsgElementConstructor.rps(resultId));
}break;
}
}

View File

@@ -63,7 +63,6 @@ export function unregisterWsEventSender(ws: WebSocketClass) {
export function postWsEvent(event: PostEventType) {
for (const ws of eventWSList) {
log(ws)
new Promise(() => {
wsReply(ws, event);
}).then()

View File

@@ -117,7 +117,9 @@ export enum OB11MessageDataType {
node = "node", // 合并转发消息节点
forward = "forward", // 合并转发消息,用于上报
xml = "xml",
poke = "poke"
poke = "poke",
dice = "dice",
RPS = "rps"
}
export interface OB11MessageMFace{
@@ -126,6 +128,20 @@ export interface OB11MessageMFace{
text: string
}
}
export interface OB11MessageDice{
type: OB11MessageDataType.dice,
data: {
result: number
}
}
export interface OB11MessageRPS{
type: OB11MessageDataType.RPS,
data: {
result: number
}
}
export interface OB11MessageText {
type: OB11MessageDataType.text,
data: {
@@ -226,7 +242,8 @@ export type OB11MessageData =
OB11MessageFace | OB11MessageMFace |
OB11MessageAt | OB11MessageReply |
OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo |
OB11MessageNode | OB11MessageCustomMusic | OB11MessageJson | OB11MessagePoke
OB11MessageNode | OB11MessageCustomMusic | OB11MessageJson | OB11MessagePoke |
OB11MessageDice | OB11MessageRPS
export interface OB11PostSendMsg {
message_type?: "private" | "group"

View File

@@ -1 +1 @@
export const version = "3.21.0"
export const version = "3.22.0"