mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-16 13:01:14 +00:00
chore: obApi
This commit is contained in:
parent
518ff48e97
commit
6605d3812a
7
src/common/utils/qqlevel.ts
Normal file
7
src/common/utils/qqlevel.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// QQ等级换算
|
||||||
|
import { QQLevel } from '@/core/entities';
|
||||||
|
|
||||||
|
export function calcQQLevel(level: QQLevel) {
|
||||||
|
const { crownNum, sunNum, moonNum, starNum } = level;
|
||||||
|
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||||
|
}
|
@ -1,17 +1,15 @@
|
|||||||
import { requireMinNTQQBuild } from '@/common/utils/QQBasicInfo';
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { BuddyCategoryType } from '@/core/entities/';
|
import { OB11Constructor } from '@/onebot/helper/constructor';
|
||||||
import { NTQQFriendApi } from '@/core';
|
|
||||||
import { OB11Constructor } from '@/onebot11/constructor';
|
|
||||||
|
|
||||||
export class GetFriendWithCategory extends BaseAction<void, any> {
|
export class GetFriendWithCategory extends BaseAction<void, any> {
|
||||||
actionName = ActionName.GetFriendsWithCategory;
|
actionName = ActionName.GetFriendsWithCategory;
|
||||||
|
|
||||||
protected async _handle(payload: void) {
|
protected async _handle(payload: void) {
|
||||||
if (requireMinNTQQBuild('26702')) {
|
if (this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
|
||||||
//全新逻辑
|
//全新逻辑
|
||||||
return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2ExWithCate(true));
|
return OB11Constructor.friendsV2(await this.CoreContext.getApiContext().FriendApi.getBuddyV2ExWithCate(true));
|
||||||
} else {
|
} else {
|
||||||
throw new Error('this ntqq version not support, must be 26702 or later');
|
throw new Error('this ntqq version not support, must be 26702 or later');
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { GroupNotify, GroupNotifyStatus } from '@/core/entities';
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { NTQQUserApi } from '@/core/apis/user';
|
|
||||||
import { NTQQGroupApi } from '@/core/apis/group';
|
import { NTQQGroupApi } from '@/core/apis/group';
|
||||||
|
|
||||||
interface OB11GroupRequestNotify {
|
interface OB11GroupRequestNotify {
|
||||||
@ -14,7 +12,7 @@ export default class GetGroupAddRequest extends BaseAction<null, OB11GroupReques
|
|||||||
actionName = ActionName.GetGroupIgnoreAddRequest;
|
actionName = ActionName.GetGroupIgnoreAddRequest;
|
||||||
|
|
||||||
protected async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
|
protected async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
|
||||||
const data = await NTQQGroupApi.getGroupIgnoreNotifies();
|
const data = await this.CoreContext.getApiContext().GroupApi.getGroupIgnoreNotifies();
|
||||||
// log(data);
|
// log(data);
|
||||||
// const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE);
|
// const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE);
|
||||||
// const returnData: OB11GroupRequestNotify[] = [];
|
// const returnData: OB11GroupRequestNotify[] = [];
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { selfInfo } from '@/core/data';
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { NTQQUserApi } from '@/core/apis';
|
|
||||||
|
|
||||||
export class GetProfileLike extends BaseAction<void, any> {
|
export class GetProfileLike extends BaseAction<void, any> {
|
||||||
actionName = ActionName.GetProfileLike;
|
actionName = ActionName.GetProfileLike;
|
||||||
protected async _handle(payload: void) {
|
protected async _handle(payload: void) {
|
||||||
const ret = await NTQQUserApi.getProfileLike(selfInfo.uid);
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
|
const ret = await NTQQUserApi.getProfileLike(this.CoreContext.selfInfo.uid);
|
||||||
const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos;
|
const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos;
|
||||||
for (let i = 0; i < listdata.length; i++) {
|
for (let i = 0; i < listdata.length; i++) {
|
||||||
listdata[i].uin = parseInt((await NTQQUserApi.getUinByUid(listdata[i].uid)) || '');
|
listdata[i].uin = parseInt((await NTQQUserApi.getUinByUid(listdata[i].uid)) || '');
|
||||||
|
@ -6,6 +6,7 @@ export class GetRobotUinRange extends BaseAction<void, Array<any>> {
|
|||||||
|
|
||||||
protected async _handle(payload: void) {
|
protected async _handle(payload: void) {
|
||||||
// console.log(await NTQQUserApi.getRobotUinRange());
|
// console.log(await NTQQUserApi.getRobotUinRange());
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
return await NTQQUserApi.getRobotUinRange();
|
return await NTQQUserApi.getRobotUinRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import { ActionName, BaseCheckResult } from '../types';
|
|||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { NTQQUserApi } from '@/core/apis/user';
|
import { NTQQUserApi } from '@/core/apis/user';
|
||||||
import { checkFileReceived, uri2local } from '@/common/utils/file';
|
import { checkFileReceived, uri2local } from '@/common/utils/file';
|
||||||
import { NTQQGroupApi } from '@/core';
|
|
||||||
// import { log } from "../../../common/utils";
|
// import { log } from "../../../common/utils";
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
@ -26,6 +25,7 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
protected async _handle(payload: Payload): Promise<any> {
|
protected async _handle(payload: Payload): Promise<any> {
|
||||||
|
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
|
||||||
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
|
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||||
|
@ -18,6 +18,7 @@ export class SetLongNick extends BaseAction<Payload, any> {
|
|||||||
actionName = ActionName.SetLongNick;
|
actionName = ActionName.SetLongNick;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
const ret = await NTQQUserApi.setLongNick(payload.longNick);
|
const ret = await NTQQUserApi.setLongNick(payload.longNick);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ export class SetOnlineStatus extends BaseAction<Payload, null> {
|
|||||||
// { status: 50, extStatus: 0, batteryStatus: 0 }
|
// { status: 50, extStatus: 0, batteryStatus: 0 }
|
||||||
// { status: 60, extStatus: 0, batteryStatus: 0 }
|
// { status: 60, extStatus: 0, batteryStatus: 0 }
|
||||||
// { status: 70, extStatus: 0, batteryStatus: 0 }
|
// { status: 70, extStatus: 0, batteryStatus: 0 }
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
const ret = await NTQQUserApi.setSelfOnlineStatus(payload.status, payload.extStatus, payload.batteryStatus);
|
const ret = await NTQQUserApi.setSelfOnlineStatus(payload.status, payload.extStatus, payload.batteryStatus);
|
||||||
if (ret.result !== 0) {
|
if (ret.result !== 0) {
|
||||||
throw new Error('设置在线状态失败');
|
throw new Error('设置在线状态失败');
|
||||||
|
@ -24,6 +24,7 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
protected async _handle(payload: Payload): Promise<null> {
|
protected async _handle(payload: Payload): Promise<null> {
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
|
const { path, isLocal, errMsg,success } = (await uri2local(payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||||
|
@ -20,6 +20,7 @@ export class SetSelfProfile extends BaseAction<Payload, any | null> {
|
|||||||
actionName = ActionName.SetSelfProfile;
|
actionName = ActionName.SetSelfProfile;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
const ret = await NTQQUserApi.modifySelfProfile({
|
const ret = await NTQQUserApi.modifySelfProfile({
|
||||||
nick: payload.nick,
|
nick: payload.nick,
|
||||||
longNick: payload.longNick,
|
longNick: payload.longNick,
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import BaseAction from '../BaseAction';
|
|
||||||
import { ActionName, BaseCheckResult } from '../types';
|
|
||||||
import { napCatCore, NTQQGroupApi } from '@/core';
|
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
||||||
|
|
||||||
const SchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
cmd: { type: 'string' },
|
|
||||||
param: { type: 'string' }
|
|
||||||
},
|
|
||||||
required: ['cmd', 'param'],
|
|
||||||
} as const satisfies JSONSchema;
|
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
|
||||||
|
|
||||||
export default class TestApi01 extends BaseAction<Payload, any> {
|
|
||||||
actionName = ActionName.TestApi01;
|
|
||||||
// 用不着复杂检测
|
|
||||||
protected async check(payload: Payload): Promise<BaseCheckResult> {
|
|
||||||
return {
|
|
||||||
valid: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
protected async _handle(payload: Payload): Promise<any> {
|
|
||||||
return await napCatCore.session.getMsgService().sendSsoCmdReqByContend(payload.cmd, payload.param);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,7 @@
|
|||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName, BaseCheckResult } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { NTQQSystemApi, NTQQUserApi } from '@/core/apis';
|
import { NTQQSystemApi } from '@/core/apis';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import Ajv from 'ajv';
|
|
||||||
// 设置在线状态
|
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { NTQQGroupApi, NTQQUserApi } from '@/core';
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { BuddyCategoryType } from '@/core/entities/';
|
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
@ -20,6 +18,8 @@ export class sharePeer extends BaseAction<Payload, any> {
|
|||||||
actionName = ActionName.SharePeer;
|
actionName = ActionName.SharePeer;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
|
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
|
||||||
if (payload.group_id) {
|
if (payload.group_id) {
|
||||||
return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id);
|
return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id);
|
||||||
} else if (payload.user_id) {
|
} else if (payload.user_id) {
|
||||||
@ -40,6 +40,8 @@ export class shareGroupEx extends BaseAction<PayloadGroupEx, any> {
|
|||||||
actionName = ActionName.ShareGroupEx;
|
actionName = ActionName.ShareGroupEx;
|
||||||
PayloadSchema = SchemaDataGroupEx;
|
PayloadSchema = SchemaDataGroupEx;
|
||||||
protected async _handle(payload: PayloadGroupEx) {
|
protected async _handle(payload: PayloadGroupEx) {
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
|
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
|
||||||
return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id);
|
return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,6 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
|
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -18,6 +16,7 @@ export class DelGroupFile extends BaseAction<Payload, any> {
|
|||||||
actionName = ActionName.DelGroupFile;
|
actionName = ActionName.DelGroupFile;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
|
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
|
||||||
return await NTQQGroupApi.DelGroupFile(payload.group_id.toString(), [payload.file_id]);
|
return await NTQQGroupApi.DelGroupFile(payload.group_id.toString(), [payload.file_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types';
|
import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types';
|
||||||
import { NTQQMsgApi } from '@/core/apis';
|
import { NTQQMsgApi } from '@/core/apis';
|
||||||
import { OB11Constructor } from '../../constructor';
|
import { OB11Constructor } from '../../helper/constructor';
|
||||||
import { ActionName, BaseCheckResult } from '../types';
|
import { ActionName, BaseCheckResult } from '../types';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import { MessageUnique } from '@/common/utils/MessageUnique';
|
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||||
@ -24,6 +24,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
|
|||||||
actionName = ActionName.GoCQHTTP_GetForwardMsg;
|
actionName = ActionName.GoCQHTTP_GetForwardMsg;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload): Promise<any> {
|
protected async _handle(payload: Payload): Promise<any> {
|
||||||
|
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
|
||||||
const msgId = payload.message_id || payload.id;
|
const msgId = payload.message_id || payload.id;
|
||||||
if (!msgId) {
|
if (!msgId) {
|
||||||
throw Error('message_id is required');
|
throw Error('message_id is required');
|
||||||
|
@ -3,9 +3,8 @@ import { OB11Message, OB11User } from '../../types';
|
|||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { ChatType, RawMessage } from '@/core/entities';
|
import { ChatType, RawMessage } from '@/core/entities';
|
||||||
import { NTQQMsgApi } from '@/core/apis/msg';
|
import { NTQQMsgApi } from '@/core/apis/msg';
|
||||||
import { OB11Constructor } from '../../constructor';
|
import { OB11Constructor } from '../../helper/constructor';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import { NTQQFriendApi, NTQQUserApi } from '@/core';
|
|
||||||
import { MessageUnique } from '@/common/utils/MessageUnique';
|
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
@ -29,6 +28,9 @@ export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
|
|||||||
actionName = ActionName.GetFriendMsgHistory;
|
actionName = ActionName.GetFriendMsgHistory;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload): Promise<Response> {
|
protected async _handle(payload: Payload): Promise<Response> {
|
||||||
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
|
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
|
||||||
|
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
|
||||||
//处理参数
|
//处理参数
|
||||||
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
|
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
|
||||||
const MsgCount = payload.count || 20;
|
const MsgCount = payload.count || 20;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { WebApi, WebHonorType } from '@/core/apis';
|
import { WebHonorType } from '@/core/entities';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -21,6 +21,7 @@ export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> {
|
|||||||
if (!payload.type) {
|
if (!payload.type) {
|
||||||
payload.type = WebHonorType.ALL;
|
payload.type = WebHonorType.ALL;
|
||||||
}
|
}
|
||||||
return await WebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
|
const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
|
||||||
|
return await NTQQWebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { OB11Message, OB11User } from '../../types';
|
import { OB11Message, OB11User } from '../../types';
|
||||||
import { getGroup, groups } from '@/core/data';
|
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { ChatType, Peer, RawMessage } from '@/core/entities';
|
import { ChatType, Peer, RawMessage } from '@/core/entities';
|
||||||
import { NTQQMsgApi } from '@/core/apis/msg';
|
import { NTQQMsgApi } from '@/core/apis/msg';
|
||||||
import { OB11Constructor } from '../../constructor';
|
import { OB11Constructor } from '../../helper/constructor';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import { MessageUnique } from '@/common/utils/MessageUnique';
|
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||||
interface Response {
|
interface Response {
|
||||||
@ -28,13 +27,11 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
|
|||||||
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
|
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
|
||||||
PayloadSchema = SchemaData;
|
PayloadSchema = SchemaData;
|
||||||
protected async _handle(payload: Payload): Promise<Response> {
|
protected async _handle(payload: Payload): Promise<Response> {
|
||||||
|
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
|
||||||
//处理参数
|
//处理参数
|
||||||
const group = await getGroup(payload.group_id.toString());
|
|
||||||
const isReverseOrder = payload.reverseOrder || true;
|
const isReverseOrder = payload.reverseOrder || true;
|
||||||
const MsgCount = payload.count || 20;
|
const MsgCount = payload.count || 20;
|
||||||
const peer: Peer = { chatType: ChatType.group, peerUid: payload.group_id.toString() };
|
const peer: Peer = { chatType: ChatType.group, peerUid: payload.group_id.toString() };
|
||||||
if (!group) throw `群${payload.group_id}不存在`;
|
|
||||||
|
|
||||||
//拉取消息
|
//拉取消息
|
||||||
let msgList: RawMessage[];
|
let msgList: RawMessage[];
|
||||||
if (!payload.message_seq || payload.message_seq == 0) {
|
if (!payload.message_seq || payload.message_seq == 0) {
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { OB11User, OB11UserSex } from '../../types';
|
import { OB11User, OB11UserSex } from '../../types';
|
||||||
import { OB11Constructor } from '../../constructor';
|
import { OB11Constructor } from '../../helper/constructor';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { NTQQUserApi } from '@/core/apis/user';
|
import { NTQQUserApi } from '@/core/apis/user';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import { calcQQLevel } from '@/common/utils/qqlevel';
|
import { calcQQLevel } from '@/common/utils/qqlevel';
|
||||||
import { requireMinNTQQBuild } from '@/common/utils/QQBasicInfo';
|
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -21,7 +19,7 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
|||||||
actionName = ActionName.GoCQHTTP_GetStrangerInfo;
|
actionName = ActionName.GoCQHTTP_GetStrangerInfo;
|
||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<OB11User> {
|
protected async _handle(payload: Payload): Promise<OB11User> {
|
||||||
if (!requireMinNTQQBuild('26702')) {
|
const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
|
||||||
const user_id = payload.user_id.toString();
|
const user_id = payload.user_id.toString();
|
||||||
const extendData = await NTQQUserApi.getUserDetailInfoByUin(user_id);
|
const extendData = await NTQQUserApi.getUserDetailInfoByUin(user_id);
|
||||||
const uid = (await NTQQUserApi.getUidByUin(user_id))!;
|
const uid = (await NTQQUserApi.getUidByUin(user_id))!;
|
||||||
@ -41,26 +39,5 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
|||||||
}
|
}
|
||||||
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
|
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
|
||||||
return OB11Constructor.stranger(data);
|
return OB11Constructor.stranger(data);
|
||||||
} else {
|
|
||||||
const user_id = payload.user_id.toString();
|
|
||||||
const extendData = await NTQQUserApi.getUserDetailInfoByUinV2(user_id);
|
|
||||||
//console.log(extendData);
|
|
||||||
const uid = (await NTQQUserApi.getUidByUin(user_id))!;
|
|
||||||
if (!uid || uid.indexOf('*') != -1) {
|
|
||||||
const ret = {
|
|
||||||
...extendData,
|
|
||||||
user_id: parseInt(extendData.detail.uin) || 0,
|
|
||||||
nickname: extendData.detail.simpleInfo.coreInfo.nick,
|
|
||||||
sex: OB11UserSex.unknown,
|
|
||||||
age: 0,
|
|
||||||
level: extendData.detail.commonExt.qqLevel && calcQQLevel(extendData.detail.commonExt.qqLevel) || 0,
|
|
||||||
login_days: 0,
|
|
||||||
uid: ''
|
|
||||||
};
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
|
|
||||||
return OB11Constructor.stranger(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { log } from '@/common/utils/log';
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { QuickAction, QuickActionEvent, handleQuickOperation } from '@/onebot11/server/postOB11Event';
|
import { QuickAction, QuickActionEvent, handleQuickOperation } from '@/onebot11/server/postOB11Event';
|
||||||
|
679
src/onebot/helper/constructor.ts
Normal file
679
src/onebot/helper/constructor.ts
Normal file
@ -0,0 +1,679 @@
|
|||||||
|
import fastXmlParser, { XMLParser } from 'fast-xml-parser';
|
||||||
|
import {
|
||||||
|
OB11Group,
|
||||||
|
OB11GroupMember,
|
||||||
|
OB11GroupMemberRole,
|
||||||
|
OB11Message,
|
||||||
|
OB11MessageData,
|
||||||
|
OB11MessageDataType,
|
||||||
|
OB11User,
|
||||||
|
OB11UserSex
|
||||||
|
} from '../types';
|
||||||
|
import {
|
||||||
|
AtType,
|
||||||
|
ChatType,
|
||||||
|
FaceIndex,
|
||||||
|
Friend,
|
||||||
|
FriendV2,
|
||||||
|
GrayTipElementSubType,
|
||||||
|
Group,
|
||||||
|
GroupMember,
|
||||||
|
Peer,
|
||||||
|
RawMessage,
|
||||||
|
SelfInfo,
|
||||||
|
Sex,
|
||||||
|
TipGroupElementType,
|
||||||
|
User,
|
||||||
|
VideoElement
|
||||||
|
} from '@/core/entities';
|
||||||
|
import { EventType } from '../event/OB11BaseEvent';
|
||||||
|
import { encodeCQCode } from './cqcode';
|
||||||
|
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
|
||||||
|
import { OB11GroupBanEvent } from '../event/notice/OB11GroupBanEvent';
|
||||||
|
import { OB11GroupUploadNoticeEvent } from '../event/notice/OB11GroupUploadNoticeEvent';
|
||||||
|
import { OB11GroupNoticeEvent } from '../event/notice/OB11GroupNoticeEvent';
|
||||||
|
import { calcQQLevel } from '@/common/utils/qqlevel';
|
||||||
|
import { sleep, UUIDConverter } from '@/common/utils/helper';
|
||||||
|
import { OB11GroupTitleEvent } from '../event/notice/OB11GroupTitleEvent';
|
||||||
|
import { OB11GroupCardEvent } from '../event/notice/OB11GroupCardEvent';
|
||||||
|
import { OB11GroupDecreaseEvent } from '../event/notice/OB11GroupDecreaseEvent';
|
||||||
|
import { NTQQFileApi, NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
|
||||||
|
import { OB11GroupMsgEmojiLikeEvent } from '@/onebot/event/notice/OB11MsgEmojiLikeEvent';
|
||||||
|
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from '../event/notice/OB11PokeEvent';
|
||||||
|
import { OB11FriendAddNoticeEvent } from '../event/notice/OB11FriendAddNoticeEvent';
|
||||||
|
import { OB11BaseNoticeEvent } from '../event/notice/OB11BaseNoticeEvent';
|
||||||
|
import { OB11GroupEssenceEvent } from '../event/notice/OB11GroupEssenceEvent';
|
||||||
|
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||||
|
|
||||||
|
|
||||||
|
export class OB11Constructor {
|
||||||
|
static async message(msg: RawMessage): Promise<OB11Message> {
|
||||||
|
const { messagePostFormat } = ob11Config;
|
||||||
|
const message_type = msg.chatType == ChatType.group ? 'group' : 'private';
|
||||||
|
const resMsg: OB11Message = {
|
||||||
|
self_id: parseInt(selfInfo.uin),
|
||||||
|
user_id: parseInt(msg.senderUin!),
|
||||||
|
time: parseInt(msg.msgTime) || Date.now(),
|
||||||
|
message_id: msg.id!,
|
||||||
|
message_seq: msg.id!,
|
||||||
|
real_id: msg.id!,
|
||||||
|
message_type: msg.chatType == ChatType.group ? 'group' : 'private',
|
||||||
|
sender: {
|
||||||
|
user_id: parseInt(msg.senderUin || '0'),
|
||||||
|
nickname: msg.sendNickName,
|
||||||
|
card: msg.sendMemberName || '',
|
||||||
|
},
|
||||||
|
raw_message: '',
|
||||||
|
font: 14,
|
||||||
|
sub_type: 'friend',
|
||||||
|
message: messagePostFormat === 'string' ? '' : [],
|
||||||
|
message_format: messagePostFormat === 'string' ? 'string' : 'array',
|
||||||
|
post_type: selfInfo.uin == msg.senderUin ? EventType.MESSAGE_SENT : EventType.MESSAGE,
|
||||||
|
};
|
||||||
|
if (msg.chatType == ChatType.group) {
|
||||||
|
resMsg.sub_type = 'normal'; // 这里go-cqhttp是group,而onebot11标准是normal, 蛋疼
|
||||||
|
resMsg.group_id = parseInt(msg.peerUin);
|
||||||
|
let member = await getGroupMember(msg.peerUin, msg.senderUin!);
|
||||||
|
if (!member) {
|
||||||
|
//直接去QQNative取
|
||||||
|
const memberList = await NTQQGroupApi.getGroupMembers(msg.peerUin);
|
||||||
|
member = memberList.get(msg.senderUin!);
|
||||||
|
}
|
||||||
|
if (member) {
|
||||||
|
resMsg.sender.role = OB11Constructor.groupMemberRole(member.role);
|
||||||
|
resMsg.sender.nickname = member.nick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg.chatType == ChatType.friend) {
|
||||||
|
resMsg.sub_type = 'friend';
|
||||||
|
resMsg.sender.nickname = (await NTQQUserApi.getUserDetailInfo(msg.senderUid)).nick;
|
||||||
|
//const user = await NTQQUserApi.getUserDetailInfoByUin(msg.senderUin!);
|
||||||
|
//resMsg.sender.nickname = user.info.nick;
|
||||||
|
}
|
||||||
|
else if (msg.chatType == ChatType.temp) {
|
||||||
|
resMsg.sub_type = 'group';
|
||||||
|
const tempGroupCode = tempGroupCodeMap[msg.peerUin];
|
||||||
|
if (tempGroupCode) {
|
||||||
|
resMsg.group_id = parseInt(tempGroupCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const element of msg.elements) {
|
||||||
|
let message_data: OB11MessageData = {
|
||||||
|
data: {} as any,
|
||||||
|
type: 'unknown' as any
|
||||||
|
};
|
||||||
|
if (element.textElement && element.textElement?.atType !== AtType.notAt) {
|
||||||
|
let qq: `${number}` | 'all';
|
||||||
|
let name: string | undefined;
|
||||||
|
if (element.textElement.atType == AtType.atAll) {
|
||||||
|
qq = 'all';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const { atNtUid, content } = element.textElement;
|
||||||
|
let atQQ = element.textElement.atUid;
|
||||||
|
if (!atQQ || atQQ === '0') {
|
||||||
|
const atMember = await getGroupMember(msg.peerUin, atNtUid);
|
||||||
|
if (atMember) {
|
||||||
|
atQQ = atMember.uin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (atQQ) {
|
||||||
|
qq = atQQ as `${number}`;
|
||||||
|
name = content.replace('@', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message_data = {
|
||||||
|
type: OB11MessageDataType.at,
|
||||||
|
data: {
|
||||||
|
qq: qq!,
|
||||||
|
name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (element.textElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.text;
|
||||||
|
|
||||||
|
let text = element.textElement.content;
|
||||||
|
if (!text.trim()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 兼容 9.7.x 换行符
|
||||||
|
if (text.indexOf('\n') === -1 && text.indexOf('\r\n') === -1) {
|
||||||
|
text = text.replace(/\r/g, '\n');
|
||||||
|
}
|
||||||
|
message_data['data']['text'] = text;
|
||||||
|
}
|
||||||
|
else if (element.replyElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.reply;
|
||||||
|
//log("收到回复消息", element.replyElement);
|
||||||
|
try {
|
||||||
|
const records = msg.records.find(msgRecord => msgRecord.msgId === element.replyElement.sourceMsgIdInRecords);
|
||||||
|
const peer = {
|
||||||
|
chatType: msg.chatType,
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
guildId: '',
|
||||||
|
};
|
||||||
|
let replyMsg: RawMessage | undefined;
|
||||||
|
if (!records) throw new Error('找不到回复消息');
|
||||||
|
replyMsg = (await NTQQMsgApi.getMsgsBySeqAndCount({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, element.replyElement.replayMsgSeq, 1, true, true)).msgList[0];
|
||||||
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
|
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0];
|
||||||
|
}
|
||||||
|
if (msg.peerUin == '284840486') {
|
||||||
|
//合并消息内侧 消息具体定位不到
|
||||||
|
}
|
||||||
|
if ((!replyMsg || records.msgRandom !== replyMsg.msgRandom) && msg.peerUin !== '284840486') {
|
||||||
|
throw new Error('回复消息消息验证失败');
|
||||||
|
}
|
||||||
|
message_data['data']['id'] = MessageUnique.createMsg({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, replyMsg.msgId)?.toString();
|
||||||
|
//log("找到回复消息", message_data['data']['id'], replyMsg.msgList[0].msgId)
|
||||||
|
} catch (e: any) {
|
||||||
|
message_data['type'] = 'unknown' as any;
|
||||||
|
message_data['data'] = undefined;
|
||||||
|
logError('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (element.picElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.image;
|
||||||
|
// message_data["data"]["file"] = element.picElement.sourcePath
|
||||||
|
message_data['data']['file'] = element.picElement.fileName;
|
||||||
|
message_data['data']['subType'] = element.picElement.picSubType;
|
||||||
|
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId);
|
||||||
|
// message_data["data"]["path"] = element.picElement.sourcePath
|
||||||
|
|
||||||
|
try {
|
||||||
|
message_data['data']['url'] = await NTQQFileApi.getImageUrl(element.picElement);
|
||||||
|
} catch (e: any) {
|
||||||
|
logError('获取图片url失败', e.stack);
|
||||||
|
}
|
||||||
|
//console.log(message_data['data']['url'])
|
||||||
|
// message_data["data"]["file_id"] = element.picElement.fileUuid
|
||||||
|
message_data['data']['file_size'] = element.picElement.fileSize;
|
||||||
|
}
|
||||||
|
else if (element.fileElement) {
|
||||||
|
const FileElement = element.fileElement;
|
||||||
|
message_data['type'] = OB11MessageDataType.file;
|
||||||
|
message_data['data']['file'] = FileElement.fileName;
|
||||||
|
message_data['data']['path'] = FileElement.filePath;
|
||||||
|
message_data['data']['url'] = FileElement.filePath;
|
||||||
|
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId);
|
||||||
|
message_data['data']['file_size'] = FileElement.fileSize;
|
||||||
|
await NTQQFileApi.addFileCache({
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
chatType: msg.chatType,
|
||||||
|
guildId: '',
|
||||||
|
},
|
||||||
|
msg.msgId,
|
||||||
|
msg.msgSeq,
|
||||||
|
msg.senderUid,
|
||||||
|
element.elementId,
|
||||||
|
element.elementType.toString(),
|
||||||
|
FileElement.fileSize,
|
||||||
|
FileElement.fileName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (element.videoElement) {
|
||||||
|
const videoElement: VideoElement = element.videoElement;
|
||||||
|
//读取视频链接并兜底
|
||||||
|
let videoUrl;//Array
|
||||||
|
if (msg.peerUin = '284840486') {
|
||||||
|
//合并消息内部 应该进行特殊处理 可能需要重写peer 待测试与研究 Mlikiowa Taged TODO
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
|
||||||
|
videoUrl = await NTQQFileApi.getVideoUrl({
|
||||||
|
chatType: msg.chatType,
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
guildId: '0'
|
||||||
|
}, msg.msgId, element.elementId);
|
||||||
|
} catch (error) {
|
||||||
|
videoUrl = undefined;
|
||||||
|
}
|
||||||
|
//读取在线URL
|
||||||
|
let videoDownUrl = undefined;
|
||||||
|
|
||||||
|
if (videoUrl) {
|
||||||
|
const videoDownUrlTemp = videoUrl.find((url) => { if (url.url) { return true; } return false; });
|
||||||
|
if (videoDownUrlTemp) {
|
||||||
|
videoDownUrl = videoDownUrlTemp.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//开始兜底
|
||||||
|
if (!videoDownUrl) {
|
||||||
|
videoDownUrl = videoElement.filePath;
|
||||||
|
}
|
||||||
|
message_data['type'] = OB11MessageDataType.video;
|
||||||
|
message_data['data']['file'] = videoElement.fileName;
|
||||||
|
message_data['data']['path'] = videoDownUrl;
|
||||||
|
message_data['data']['url'] = videoDownUrl;
|
||||||
|
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId);
|
||||||
|
message_data['data']['file_size'] = videoElement.fileSize;
|
||||||
|
|
||||||
|
await NTQQFileApi.addFileCache({
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
chatType: msg.chatType,
|
||||||
|
guildId: '',
|
||||||
|
},
|
||||||
|
msg.msgId,
|
||||||
|
msg.msgSeq,
|
||||||
|
msg.senderUid,
|
||||||
|
element.elementId,
|
||||||
|
element.elementType.toString(),
|
||||||
|
videoElement.fileSize || '0',
|
||||||
|
videoElement.fileName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (element.pttElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.voice;
|
||||||
|
message_data['data']['file'] = element.pttElement.fileName;
|
||||||
|
message_data['data']['path'] = element.pttElement.filePath;
|
||||||
|
//message_data['data']['file_id'] = element.pttElement.fileUuid;
|
||||||
|
message_data['data']['file_id'] = UUIDConverter.encode(msg.peerUin, msg.msgId);
|
||||||
|
message_data['data']['file_size'] = element.pttElement.fileSize;
|
||||||
|
await NTQQFileApi.addFileCache({
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
chatType: msg.chatType,
|
||||||
|
guildId: '',
|
||||||
|
},
|
||||||
|
msg.msgId,
|
||||||
|
msg.msgSeq,
|
||||||
|
msg.senderUid,
|
||||||
|
element.elementId,
|
||||||
|
element.elementType.toString(),
|
||||||
|
element.pttElement.fileSize || '0',
|
||||||
|
element.pttElement.fileUuid || ''
|
||||||
|
);
|
||||||
|
//以uuid作为文件名
|
||||||
|
}
|
||||||
|
else if (element.arkElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.json;
|
||||||
|
message_data['data']['data'] = element.arkElement.bytesData;
|
||||||
|
}
|
||||||
|
else if (element.faceElement) {
|
||||||
|
const faceId = element.faceElement.faceIndex;
|
||||||
|
if (faceId === FaceIndex.dice) {
|
||||||
|
message_data['type'] = OB11MessageDataType.dice;
|
||||||
|
message_data['data']['result'] = element.faceElement.resultId;
|
||||||
|
}
|
||||||
|
else if (faceId === FaceIndex.RPS) {
|
||||||
|
message_data['type'] = OB11MessageDataType.RPS;
|
||||||
|
message_data['data']['result'] = element.faceElement.resultId;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message_data['type'] = OB11MessageDataType.face;
|
||||||
|
message_data['data']['id'] = element.faceElement.faceIndex.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (element.marketFaceElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.mface;
|
||||||
|
message_data['data']['summary'] = element.marketFaceElement.faceName;
|
||||||
|
const md5 = element.marketFaceElement.emojiId;
|
||||||
|
// 取md5的前两位
|
||||||
|
const dir = md5.substring(0, 2);
|
||||||
|
// 获取组装url
|
||||||
|
// const url = `https://p.qpic.cn/CDN_STATIC/0/data/imgcache/htdocs/club/item/parcel/item/${dir}/${md5}/300x300.gif?max_age=31536000`;
|
||||||
|
const url = `https://gxh.vip.qq.com/club/item/parcel/item/${dir}/${md5}/raw300.gif`;
|
||||||
|
message_data['data']['url'] = url;
|
||||||
|
message_data['data']['emoji_id'] = element.marketFaceElement.emojiId;
|
||||||
|
message_data['data']['emoji_package_id'] = String(element.marketFaceElement.emojiPackageId);
|
||||||
|
message_data['data']['key'] = element.marketFaceElement.key;
|
||||||
|
mFaceCache.set(md5, element.marketFaceElement.faceName);
|
||||||
|
}
|
||||||
|
else if (element.markdownElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.markdown;
|
||||||
|
message_data['data']['data'] = element.markdownElement.content;
|
||||||
|
}
|
||||||
|
else if (element.multiForwardMsgElement) {
|
||||||
|
message_data['type'] = OB11MessageDataType.forward;
|
||||||
|
message_data['data']['id'] = msg.msgId;
|
||||||
|
const ParentMsgPeer = msg.parentMsgPeer ?? { chatType: msg.chatType, guildId: '', peerUid: msg.peerUid };
|
||||||
|
//判断是否在合并消息内
|
||||||
|
msg.parentMsgIdList = msg.parentMsgIdList ?? [];
|
||||||
|
//首次列表不存在则开始创建
|
||||||
|
msg.parentMsgIdList.push(msg.msgId);
|
||||||
|
//let parentMsgId = msg.parentMsgIdList[msg.parentMsgIdList.length - 2 < 0 ? 0 : msg.parentMsgIdList.length - 2];
|
||||||
|
//加入自身MsgId
|
||||||
|
let MultiMsgs = (await NTQQMsgApi.getMultiMsg(ParentMsgPeer, msg.parentMsgIdList[0], msg.msgId))?.msgList;
|
||||||
|
//拉取下级消息
|
||||||
|
if (!MultiMsgs) continue;
|
||||||
|
//拉取失败则跳过
|
||||||
|
message_data['data']['content'] = [];
|
||||||
|
for (let MultiMsg of MultiMsgs) {
|
||||||
|
//对每条拉取的消息传递ParentMsgPeer修正Peer
|
||||||
|
MultiMsg.parentMsgPeer = ParentMsgPeer;
|
||||||
|
MultiMsg.parentMsgIdList = msg.parentMsgIdList;
|
||||||
|
MultiMsg.id = MessageUnique.createMsg(ParentMsgPeer, MultiMsg.msgId);//该ID仅用查看 无法调用
|
||||||
|
let msgList = await OB11Constructor.message(MultiMsg);
|
||||||
|
message_data['data']['content'].push(msgList);
|
||||||
|
//console.log("合并消息", msgList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((message_data.type as string) !== 'unknown' && message_data.data) {
|
||||||
|
const cqCode = encodeCQCode(message_data);
|
||||||
|
|
||||||
|
if (messagePostFormat === 'string') {
|
||||||
|
(resMsg.message as string) += cqCode;
|
||||||
|
}
|
||||||
|
else (resMsg.message as OB11MessageData[]).push(message_data);
|
||||||
|
resMsg.raw_message += cqCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
resMsg.raw_message = resMsg.raw_message.trim();
|
||||||
|
return resMsg;
|
||||||
|
}
|
||||||
|
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent | undefined> {
|
||||||
|
if (msg.chatType !== ChatType.friend) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const element of msg.elements) {
|
||||||
|
if (element.grayTipElement) {
|
||||||
|
if (element.grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
|
||||||
|
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr);
|
||||||
|
|
||||||
|
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
|
//判断业务类型
|
||||||
|
//Poke事件
|
||||||
|
let pokedetail: any[] = json.items;
|
||||||
|
//筛选item带有uid的元素
|
||||||
|
pokedetail = pokedetail.filter(item => item.uid);
|
||||||
|
//console.log("[NapCat] 群拍一拍 群:", pokedetail, parseInt(msg.peerUid), " ", await NTQQUserApi.getUinByUid(pokedetail[0].uid), "拍了拍", await NTQQUserApi.getUinByUid(pokedetail[1].uid));
|
||||||
|
if (pokedetail.length == 2) {
|
||||||
|
return new OB11FriendPokeEvent(parseInt((await NTQQUserApi.getUinByUid(pokedetail[0].uid))!), parseInt((await NTQQUserApi.getUinByUid(pokedetail[1].uid))!), pokedetail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE
|
||||||
|
}
|
||||||
|
if (element.grayTipElement.subElementType == GrayTipElementSubType.INVITE_NEW_MEMBER) {
|
||||||
|
//好友添加成功事件
|
||||||
|
if (element.grayTipElement.xmlElement.templId === '10229' && msg.peerUin !== '') {
|
||||||
|
return new OB11FriendAddNoticeEvent(parseInt(msg.peerUin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static async GroupEvent(msg: RawMessage): Promise<OB11GroupNoticeEvent | undefined> {
|
||||||
|
if (msg.chatType !== ChatType.group) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//log("group msg", msg);
|
||||||
|
if (msg.senderUin && msg.senderUin !== '0') {
|
||||||
|
const member = await getGroupMember(msg.peerUid, msg.senderUin);
|
||||||
|
if (member && member.cardName !== msg.sendMemberName) {
|
||||||
|
const newCardName = msg.sendMemberName || '';
|
||||||
|
const event = new OB11GroupCardEvent(parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName);
|
||||||
|
member.cardName = newCardName;
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const element of msg.elements) {
|
||||||
|
const grayTipElement = element.grayTipElement;
|
||||||
|
const groupElement = grayTipElement?.groupElement;
|
||||||
|
if (groupElement) {
|
||||||
|
// log("收到群提示消息", groupElement)
|
||||||
|
if (groupElement.type == TipGroupElementType.memberIncrease) {
|
||||||
|
logDebug('收到群成员增加消息', groupElement);
|
||||||
|
await sleep(1000);
|
||||||
|
const member = await getGroupMember(msg.peerUid, groupElement.memberUid);
|
||||||
|
const memberUin = member?.uin;
|
||||||
|
// if (!memberUin) {
|
||||||
|
// memberUin = (await NTQQUserApi.getUserDetailInfo(groupElement.memberUid)).uin
|
||||||
|
// }
|
||||||
|
// log("获取新群成员QQ", memberUin)
|
||||||
|
const adminMember = await getGroupMember(msg.peerUid, groupElement.adminUid);
|
||||||
|
// log("获取同意新成员入群的管理员", adminMember)
|
||||||
|
if (memberUin) {
|
||||||
|
const operatorUin = adminMember?.uin || memberUin;
|
||||||
|
const event = new OB11GroupIncreaseEvent(parseInt(msg.peerUid), parseInt(memberUin), parseInt(operatorUin));
|
||||||
|
// log("构造群增加事件", event)
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (groupElement.type === TipGroupElementType.ban) {
|
||||||
|
logDebug('收到群群员禁言提示', groupElement);
|
||||||
|
const memberUid = groupElement.shutUp!.member.uid;
|
||||||
|
const adminUid = groupElement.shutUp!.admin.uid;
|
||||||
|
let memberUin: string = '';
|
||||||
|
let duration = parseInt(groupElement.shutUp!.duration);
|
||||||
|
const sub_type: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban';
|
||||||
|
// log('OB11被禁言事件', adminUid);
|
||||||
|
if (memberUid) {
|
||||||
|
memberUin = (await getGroupMember(msg.peerUid, memberUid))?.uin || ''; // || (await NTQQUserApi.getUserDetailInfo(memberUid))?.uin
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memberUin = '0'; // 0表示全员禁言
|
||||||
|
if (duration > 0) {
|
||||||
|
duration = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const adminUin = (await getGroupMember(msg.peerUid, adminUid))?.uin; // || (await NTQQUserApi.getUserDetailInfo(adminUid))?.uin
|
||||||
|
// log('OB11被禁言事件', memberUin, adminUin, duration, sub_type);
|
||||||
|
if (memberUin && adminUin) {
|
||||||
|
const event = new OB11GroupBanEvent(parseInt(msg.peerUid), parseInt(memberUin), parseInt(adminUin), duration, sub_type);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (groupElement.type == TipGroupElementType.kicked) {
|
||||||
|
logDebug(`收到我被踢出或退群提示, 群${msg.peerUid}`, groupElement);
|
||||||
|
deleteGroup(msg.peerUid);
|
||||||
|
NTQQGroupApi.quitGroup(msg.peerUid).then();
|
||||||
|
try {
|
||||||
|
const adminUin = (await getGroupMember(msg.peerUid, groupElement.adminUid))?.uin || (await NTQQUserApi.getUidByUin(groupElement.adminUid));
|
||||||
|
if (adminUin) {
|
||||||
|
return new OB11GroupDecreaseEvent(parseInt(msg.peerUid), parseInt(selfInfo.uin), parseInt(adminUin), 'kick_me');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return new OB11GroupDecreaseEvent(parseInt(msg.peerUid), parseInt(selfInfo.uin), 0, 'leave');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (element.fileElement) {
|
||||||
|
return new OB11GroupUploadNoticeEvent(parseInt(msg.peerUid), parseInt(msg.senderUin || ''), {
|
||||||
|
id: element.fileElement.fileUuid!,
|
||||||
|
name: element.fileElement.fileName,
|
||||||
|
size: parseInt(element.fileElement.fileSize),
|
||||||
|
busid: element.fileElement.fileBizId || 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (grayTipElement) {
|
||||||
|
//console.log('收到群提示消息', grayTipElement);
|
||||||
|
if (grayTipElement.xmlElement?.templId === '10382') {
|
||||||
|
const emojiLikeData = new fastXmlParser.XMLParser({
|
||||||
|
ignoreAttributes: false,
|
||||||
|
attributeNamePrefix: ''
|
||||||
|
}).parse(grayTipElement.xmlElement.content);
|
||||||
|
logDebug('收到表情回应我的消息', emojiLikeData);
|
||||||
|
try {
|
||||||
|
const senderUin = emojiLikeData.gtip.qq.jp;
|
||||||
|
const msgSeq = emojiLikeData.gtip.url.msgseq;
|
||||||
|
const emojiId = emojiLikeData.gtip.face.id;
|
||||||
|
|
||||||
|
const replyMsgList = (await NTQQMsgApi.getMsgsBySeqAndCount({ chatType: ChatType.group, guildId: '', peerUid: msg.peerUid }, msgSeq, 1, true, true)).msgList;
|
||||||
|
if (replyMsgList.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('表情回应消息', msgSeq, " 结算ID", replyMsgList[0].msgId);
|
||||||
|
const replyMsg = replyMsgList[0];
|
||||||
|
return new OB11GroupMsgEmojiLikeEvent(parseInt(msg.peerUid), parseInt(senderUin), MessageUnique.getShortIdByMsgId(replyMsg?.msgId!)!, [{
|
||||||
|
emoji_id: emojiId,
|
||||||
|
count: 1
|
||||||
|
}]);
|
||||||
|
} catch (e: any) {
|
||||||
|
logError('解析表情回应消息失败', e.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (grayTipElement.subElementType == GrayTipElementSubType.INVITE_NEW_MEMBER) {
|
||||||
|
logDebug('收到新人被邀请进群消息', grayTipElement);
|
||||||
|
const xmlElement = grayTipElement.xmlElement;
|
||||||
|
if (xmlElement?.content) {
|
||||||
|
const regex = /jp="(\d+)"/g;
|
||||||
|
|
||||||
|
const matches = [];
|
||||||
|
let match = null;
|
||||||
|
|
||||||
|
while ((match = regex.exec(xmlElement.content)) !== null) {
|
||||||
|
matches.push(match[1]);
|
||||||
|
}
|
||||||
|
// log("新人进群匹配到的QQ号", matches)
|
||||||
|
if (matches.length === 2) {
|
||||||
|
const [inviter, invitee] = matches;
|
||||||
|
return new OB11GroupIncreaseEvent(parseInt(msg.peerUid), parseInt(invitee), parseInt(inviter), 'invite');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//代码歧义 GrayTipElementSubType.MEMBER_NEW_TITLE
|
||||||
|
else if (grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
|
||||||
|
const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr);
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
|
//判断业务类型
|
||||||
|
//Poke事件
|
||||||
|
const pokedetail: any[] = json.items;
|
||||||
|
//筛选item带有uid的元素
|
||||||
|
const poke_uid = pokedetail.filter(item => item.uid);
|
||||||
|
if (poke_uid.length == 2) {
|
||||||
|
return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((await NTQQUserApi.getUinByUid(poke_uid[0].uid))!), parseInt((await NTQQUserApi.getUinByUid(poke_uid[1].uid))!), pokedetail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 2401) {
|
||||||
|
const searchParams = new URL(json.items[0].jp).searchParams;
|
||||||
|
const msgSeq = searchParams.get('msgSeq')!;
|
||||||
|
const Group = searchParams.get('groupCode');
|
||||||
|
const Businessid = searchParams.get('businessid');
|
||||||
|
const Peer: Peer = {
|
||||||
|
guildId: '',
|
||||||
|
chatType: ChatType.group,
|
||||||
|
peerUid: Group!
|
||||||
|
};
|
||||||
|
const msgData = await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true);
|
||||||
|
return new OB11GroupEssenceEvent(parseInt(msg.peerUid), MessageUnique.getShortIdByMsgId(msgData.msgList[0].msgId)!, parseInt(msgData.msgList[0].senderUin));
|
||||||
|
// 获取MsgSeq+Peer可获取具体消息
|
||||||
|
}
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
||||||
|
//下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE
|
||||||
|
const memberUin = json.items[1].param[0];
|
||||||
|
const title = json.items[3].txt;
|
||||||
|
logDebug('收到群成员新头衔消息', json);
|
||||||
|
return new OB11GroupTitleEvent(parseInt(msg.peerUid), parseInt(memberUin), title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static friend(friend: User): OB11User {
|
||||||
|
return {
|
||||||
|
user_id: parseInt(friend.uin),
|
||||||
|
nickname: friend.nick,
|
||||||
|
remark: friend.remark,
|
||||||
|
sex: OB11Constructor.sex(friend.sex!),
|
||||||
|
level: friend.qqLevel && calcQQLevel(friend.qqLevel) || 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static selfInfo(selfInfo: SelfInfo): OB11User {
|
||||||
|
return {
|
||||||
|
user_id: parseInt(selfInfo.uin),
|
||||||
|
nickname: selfInfo.nick,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static friendsV2(friends: FriendV2[]): OB11User[] {
|
||||||
|
const data: OB11User[] = [];
|
||||||
|
friends.forEach(friend => {
|
||||||
|
const sexValue = this.sex(friend.baseInfo.sex!);
|
||||||
|
data.push({
|
||||||
|
...friend.baseInfo,
|
||||||
|
...friend.coreInfo,
|
||||||
|
user_id: parseInt(friend.coreInfo.uin),
|
||||||
|
nickname: friend.coreInfo.nick,
|
||||||
|
remark: friend.coreInfo.nick,
|
||||||
|
sex: sexValue,
|
||||||
|
level: 0,
|
||||||
|
categroyName: friend.categroyName,
|
||||||
|
categoryId: friend.categoryId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
static friends(friends: Friend[]): OB11User[] {
|
||||||
|
const data: OB11User[] = [];
|
||||||
|
friends.forEach(friend => {
|
||||||
|
const sexValue = this.sex(friend.sex!);
|
||||||
|
data.push({ user_id: parseInt(friend.uin), nickname: friend.nick, remark: friend.remark, sex: sexValue, level: 0 });
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
||||||
|
return {
|
||||||
|
4: OB11GroupMemberRole.owner,
|
||||||
|
3: OB11GroupMemberRole.admin,
|
||||||
|
2: OB11GroupMemberRole.member
|
||||||
|
}[role];
|
||||||
|
}
|
||||||
|
|
||||||
|
static sex(sex: Sex): OB11UserSex {
|
||||||
|
const sexMap = {
|
||||||
|
[Sex.male]: OB11UserSex.male,
|
||||||
|
[Sex.female]: OB11UserSex.female,
|
||||||
|
[Sex.unknown]: OB11UserSex.unknown
|
||||||
|
};
|
||||||
|
return sexMap[sex] || OB11UserSex.unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
static groupMember(group_id: string, member: GroupMember): OB11GroupMember {
|
||||||
|
return {
|
||||||
|
group_id: parseInt(group_id),
|
||||||
|
user_id: parseInt(member.uin),
|
||||||
|
nickname: member.nick,
|
||||||
|
card: member.cardName,
|
||||||
|
sex: OB11Constructor.sex(member.sex!),
|
||||||
|
age: 0,
|
||||||
|
area: '',
|
||||||
|
level: '0',
|
||||||
|
qq_level: member.qqLevel && calcQQLevel(member.qqLevel) || 0,
|
||||||
|
join_time: 0, // 暂时没法获取
|
||||||
|
last_sent_time: 0, // 暂时没法获取
|
||||||
|
title_expire_time: 0,
|
||||||
|
unfriendly: false,
|
||||||
|
card_changeable: true,
|
||||||
|
is_robot: member.isRobot,
|
||||||
|
shut_up_timestamp: member.shutUpTime,
|
||||||
|
role: OB11Constructor.groupMemberRole(member.role),
|
||||||
|
title: member.memberSpecialTitle || '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static stranger(user: User): OB11User {
|
||||||
|
//logDebug('construct ob11 stranger', user);
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
user_id: parseInt(user.uin),
|
||||||
|
nickname: user.nick,
|
||||||
|
sex: OB11Constructor.sex(user.sex!),
|
||||||
|
age: 0,
|
||||||
|
qid: user.qid,
|
||||||
|
login_days: 0,
|
||||||
|
level: user.qqLevel && calcQQLevel(user.qqLevel) || 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static groupMembers(group: Group): OB11GroupMember[] {
|
||||||
|
//logDebug('construct ob11 group members', group);
|
||||||
|
return Array.from(groupMembers.get(group.groupCode)?.values() || []).map(m => OB11Constructor.groupMember(group.groupCode, m));
|
||||||
|
}
|
||||||
|
|
||||||
|
static group(group: Group): OB11Group {
|
||||||
|
return {
|
||||||
|
group_id: parseInt(group.groupCode),
|
||||||
|
group_name: group.groupName,
|
||||||
|
member_count: group.memberCount,
|
||||||
|
max_member_count: group.maxMember
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static groups(groups: Group[]): OB11Group[] {
|
||||||
|
return groups.map(OB11Constructor.group);
|
||||||
|
}
|
||||||
|
}
|
86
src/onebot/helper/cqcode.ts
Normal file
86
src/onebot/helper/cqcode.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { OB11MessageData } from '../types';
|
||||||
|
|
||||||
|
const pattern = /\[CQ:(\w+)((,\w+=[^,\]]*)*)\]/;
|
||||||
|
|
||||||
|
function unescape(source: string) {
|
||||||
|
return String(source)
|
||||||
|
.replace(/[/g, '[')
|
||||||
|
.replace(/]/g, ']')
|
||||||
|
.replace(/,/g, ',')
|
||||||
|
.replace(/&/g, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function from(source: string) {
|
||||||
|
const capture = pattern.exec(source);
|
||||||
|
if (!capture) return null;
|
||||||
|
const [, type, attrs] = capture;
|
||||||
|
const data: Record<string, any> = {};
|
||||||
|
attrs && attrs.slice(1).split(',').forEach((str) => {
|
||||||
|
const index = str.indexOf('=');
|
||||||
|
data[str.slice(0, index)] = unescape(str.slice(index + 1));
|
||||||
|
});
|
||||||
|
return { type, data, capture };
|
||||||
|
}
|
||||||
|
|
||||||
|
function h(type: string, data: any) {
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeCQCode(source: string): OB11MessageData[] {
|
||||||
|
const elements: any[] = [];
|
||||||
|
let result: ReturnType<typeof from>;
|
||||||
|
while ((result = from(source))) {
|
||||||
|
const { type, data, capture } = result;
|
||||||
|
if (capture.index) {
|
||||||
|
elements.push(h('text', { text: unescape(source.slice(0, capture.index)) }));
|
||||||
|
}
|
||||||
|
elements.push(h(type, data));
|
||||||
|
source = source.slice(capture.index + capture[0].length);
|
||||||
|
}
|
||||||
|
if (source) elements.push(h('text', { text: unescape(source) }));
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function encodeCQCode(data: OB11MessageData) {
|
||||||
|
const CQCodeEscapeText = (text: string) => {
|
||||||
|
return text.replace(/&/g, '&')
|
||||||
|
.replace(/\[/g, '[')
|
||||||
|
.replace(/\]/g, ']');
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const CQCodeEscape = (text: string) => {
|
||||||
|
return text.replace(/&/g, '&')
|
||||||
|
.replace(/\[/g, '[')
|
||||||
|
.replace(/\]/g, ']')
|
||||||
|
.replace(/,/g, ',');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data.type === 'text') {
|
||||||
|
return CQCodeEscapeText(data.data.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = '[CQ:' + data.type;
|
||||||
|
for (const name in data.data) {
|
||||||
|
const value = data.data[name];
|
||||||
|
if (value === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const text = value.toString();
|
||||||
|
result += `,${name}=${CQCodeEscape(text)}`;
|
||||||
|
} catch (error) {
|
||||||
|
// If it can't be converted, skip this name-value pair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += ']';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const result = parseCQCode("[CQ:at,qq=114514]早上好啊[CQ:image,file=http://baidu.com/1.jpg,type=show,id=40004]")
|
||||||
|
// const result = parseCQCode("好好好")
|
||||||
|
// console.log(JSON.stringify(result))
|
Loading…
Reference in New Issue
Block a user