From 1e35ffd7e6488c4e3a5955866b663797d952b5ed Mon Sep 17 00:00:00 2001 From: idranme Date: Tue, 24 Sep 2024 14:18:44 +0800 Subject: [PATCH 1/5] optimize --- src/common/utils/misc.ts | 7 +++++++ src/main/store.ts | 2 +- src/ntqqapi/api/group.ts | 7 +------ src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts | 4 ++-- src/onebot11/action/group/SetGroupAddRequest.ts | 3 ++- src/onebot11/action/group/SetGroupAdmin.ts | 3 ++- src/onebot11/action/group/SetGroupKick.ts | 3 ++- src/onebot11/action/group/SetGroupWholeBan.ts | 3 ++- src/onebot11/action/llonebot/GetFriendMsgHistory.ts | 4 ++-- src/onebot11/action/user/GetFriendList.ts | 3 ++- 10 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/common/utils/misc.ts b/src/common/utils/misc.ts index 5be0c73..3649051 100644 --- a/src/common/utils/misc.ts +++ b/src/common/utils/misc.ts @@ -38,3 +38,10 @@ export function mergeNewProperties(newObj: Dict, oldObj: Dict) { export function filterNullable(array: T[]) { return array.filter(e => !isNullable(e)) as NonNullable[] } + +export function parseBool(value: string) { + if (['', 'true', '1'].includes(value)) { + return true + } + return false +} diff --git a/src/main/store.ts b/src/main/store.ts index a0c31b7..3b1a6ee 100644 --- a/src/main/store.ts +++ b/src/main/store.ts @@ -30,7 +30,7 @@ export default class Store extends Service { constructor(protected ctx: Context) { super(ctx, 'store', true) - this.cache = new LimitedHashTable(1000) + this.cache = new LimitedHashTable(1000) this.initDatabase() } diff --git a/src/ntqqapi/api/group.ts b/src/ntqqapi/api/group.ts index 427d5a7..9e21170 100644 --- a/src/ntqqapi/api/group.ts +++ b/src/ntqqapi/api/group.ts @@ -156,12 +156,7 @@ export class NTQQGroupApi extends Service { } } - async kickMember( - groupCode: string, - kickUids: string[], - refuseForever = false, - kickReason = '', - ) { + async kickMember(groupCode: string, kickUids: string[], refuseForever = false, kickReason = '') { const session = getSession() if (session) { return session.getGroupService().kickMember(groupCode, kickUids, refuseForever, kickReason) diff --git a/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts b/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts index 8172491..58750c7 100644 --- a/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts +++ b/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts @@ -4,7 +4,7 @@ import { ActionName } from '../types' import { ChatType } from '@/ntqqapi/types' import { OB11Entities } from '../../entities' import { RawMessage } from '@/ntqqapi/types' -import { filterNullable } from '@/common/utils/misc' +import { filterNullable, parseBool } from '@/common/utils/misc' interface Payload { group_id: number | string @@ -23,7 +23,7 @@ export class GetGroupMsgHistory extends BaseAction { group_id: Schema.union([Number, String]).required(), message_seq: Schema.union([Number, String]), count: Schema.union([Number, String]).default(20), - reverseOrder: Schema.boolean().default(false), + reverseOrder: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(false) }) protected async _handle(payload: Payload): Promise { diff --git a/src/onebot11/action/group/SetGroupAddRequest.ts b/src/onebot11/action/group/SetGroupAddRequest.ts index 076b1e2..5666b07 100644 --- a/src/onebot11/action/group/SetGroupAddRequest.ts +++ b/src/onebot11/action/group/SetGroupAddRequest.ts @@ -1,6 +1,7 @@ import { BaseAction, Schema } from '../BaseAction' import { GroupRequestOperateTypes } from '@/ntqqapi/types' import { ActionName } from '../types' +import { parseBool } from '@/common/utils/misc' interface Payload { flag: string @@ -12,7 +13,7 @@ export default class SetGroupAddRequest extends BaseAction { actionName = ActionName.SetGroupAddRequest payloadSchema = Schema.object({ flag: Schema.string().required(), - approve: Schema.boolean().default(true), + approve: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(true), reason: Schema.string() }) diff --git a/src/onebot11/action/group/SetGroupAdmin.ts b/src/onebot11/action/group/SetGroupAdmin.ts index 74fd71b..6368950 100644 --- a/src/onebot11/action/group/SetGroupAdmin.ts +++ b/src/onebot11/action/group/SetGroupAdmin.ts @@ -1,6 +1,7 @@ import { BaseAction, Schema } from '../BaseAction' import { GroupMemberRole } from '@/ntqqapi/types' import { ActionName } from '../types' +import { parseBool } from '@/common/utils/misc' interface Payload { group_id: number | string @@ -13,7 +14,7 @@ export default class SetGroupAdmin extends BaseAction { payloadSchema = Schema.object({ group_id: Schema.union([Number, String]).required(), user_id: Schema.union([Number, String]).required(), - enable: Schema.boolean().default(true) + enable: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(true) }) protected async _handle(payload: Payload): Promise { diff --git a/src/onebot11/action/group/SetGroupKick.ts b/src/onebot11/action/group/SetGroupKick.ts index 5f8fe69..2ca7c5d 100644 --- a/src/onebot11/action/group/SetGroupKick.ts +++ b/src/onebot11/action/group/SetGroupKick.ts @@ -1,5 +1,6 @@ import { BaseAction, Schema } from '../BaseAction' import { ActionName } from '../types' +import { parseBool } from '@/common/utils/misc' interface Payload { group_id: number | string @@ -12,7 +13,7 @@ export default class SetGroupKick extends BaseAction { payloadSchema = Schema.object({ group_id: Schema.union([Number, String]).required(), user_id: Schema.union([Number, String]).required(), - reject_add_request: Schema.boolean().default(false) + reject_add_request: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(false) }) protected async _handle(payload: Payload): Promise { diff --git a/src/onebot11/action/group/SetGroupWholeBan.ts b/src/onebot11/action/group/SetGroupWholeBan.ts index 792e429..4dd0d3b 100644 --- a/src/onebot11/action/group/SetGroupWholeBan.ts +++ b/src/onebot11/action/group/SetGroupWholeBan.ts @@ -1,5 +1,6 @@ import { BaseAction, Schema } from '../BaseAction' import { ActionName } from '../types' +import { parseBool } from '@/common/utils/misc' interface Payload { group_id: number | string @@ -10,7 +11,7 @@ export default class SetGroupWholeBan extends BaseAction { actionName = ActionName.SetGroupWholeBan payloadSchema = Schema.object({ group_id: Schema.union([Number, String]).required(), - enable: Schema.boolean().default(true) + enable: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(true) }) protected async _handle(payload: Payload): Promise { diff --git a/src/onebot11/action/llonebot/GetFriendMsgHistory.ts b/src/onebot11/action/llonebot/GetFriendMsgHistory.ts index e7c3219..4f139ee 100644 --- a/src/onebot11/action/llonebot/GetFriendMsgHistory.ts +++ b/src/onebot11/action/llonebot/GetFriendMsgHistory.ts @@ -3,7 +3,7 @@ import { OB11Message } from '@/onebot11/types' import { ActionName } from '../types' import { ChatType, RawMessage } from '@/ntqqapi/types' import { OB11Entities } from '@/onebot11/entities' -import { filterNullable } from '@/common/utils/misc' +import { filterNullable, parseBool } from '@/common/utils/misc' interface Payload { user_id: number | string @@ -24,7 +24,7 @@ export class GetFriendMsgHistory extends BaseAction { message_seq: Schema.union([Number, String]), message_id: Schema.union([Number, String]), count: Schema.union([Number, String]).default(20), - reverseOrder: Schema.boolean().default(false) + reverseOrder: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(false) }) async _handle(payload: Payload): Promise { diff --git a/src/onebot11/action/user/GetFriendList.ts b/src/onebot11/action/user/GetFriendList.ts index 540702b..31d006d 100644 --- a/src/onebot11/action/user/GetFriendList.ts +++ b/src/onebot11/action/user/GetFriendList.ts @@ -3,6 +3,7 @@ import { OB11User } from '../../types' import { OB11Entities } from '../../entities' import { ActionName } from '../types' import { getBuildVersion } from '@/common/utils' +import { parseBool } from '@/common/utils/misc' interface Payload { no_cache: boolean @@ -11,7 +12,7 @@ interface Payload { export class GetFriendList extends BaseAction { actionName = ActionName.GetFriendList payloadSchema = Schema.object({ - no_cache: Schema.boolean().default(false) + no_cache: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(false) }) protected async _handle(payload: Payload) { From 032ac85c0477c6ff8d1b3e87f6e615b145561d79 Mon Sep 17 00:00:00 2001 From: idranme Date: Tue, 24 Sep 2024 19:05:16 +0800 Subject: [PATCH 2/5] refactor --- src/ntqqapi/api/file.ts | 2 +- src/ntqqapi/core.ts | 10 +- src/ntqqapi/entities.ts | 54 ++-- src/ntqqapi/types/msg.ts | 279 ++++++++---------- src/onebot11/action/file/GetFile.ts | 4 +- .../action/go-cqhttp/GetGroupEssence.ts | 2 +- .../action/go-cqhttp/GetGroupMsgHistory.ts | 5 +- .../action/go-cqhttp/SendForwardMsg.ts | 12 +- .../action/llonebot/GetFriendMsgHistory.ts | 5 +- src/onebot11/action/msg/ForwardSingleMsg.ts | 16 +- src/onebot11/action/msg/SendMsg.ts | 6 +- src/onebot11/adapter.ts | 5 - src/onebot11/entities.ts | 43 +-- src/onebot11/helper/createMessage.ts | 31 +- 14 files changed, 208 insertions(+), 266 deletions(-) diff --git a/src/ntqqapi/api/file.ts b/src/ntqqapi/api/file.ts index f063013..920f428 100644 --- a/src/ntqqapi/api/file.ts +++ b/src/ntqqapi/api/file.ts @@ -73,7 +73,7 @@ export class NTQQFileApi extends Service { } // 上传文件到QQ的文件夹 - async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType = 0) { + async uploadFile(filePath: string, elementType = ElementType.Pic, elementSubType = 0) { const fileMd5 = await calculateFileMD5(filePath) let fileName = path.basename(filePath) if (!fileName.includes('.')) { diff --git a/src/ntqqapi/core.ts b/src/ntqqapi/core.ts index 5579161..834539c 100644 --- a/src/ntqqapi/core.ts +++ b/src/ntqqapi/core.ts @@ -63,7 +63,7 @@ class Core extends Service { uids = payload.data.flatMap(item => item.buddyList.map(e => e.uid)) } for (const uid of uids) { - this.ctx.ntMsgApi.activateChat({ peerUid: uid, chatType: ChatType.friend }) + this.ctx.ntMsgApi.activateChat({ peerUid: uid, chatType: ChatType.C2C }) } this.ctx.logger.info('好友列表变动', uids.length) }) @@ -116,7 +116,7 @@ class Core extends Service { if (activatedPeerUids.includes(contact.id)) continue activatedPeerUids.push(contact.id) const peer = { peerUid: contact.id, chatType: contact.chatType } - if (contact.chatType === ChatType.temp) { + if (contact.chatType === ChatType.TempC2CFromGroup) { this.ctx.ntMsgApi.activateChatAndGetHistory(peer).then(() => { this.ctx.ntMsgApi.getMsgHistory(peer, '', 20).then(({ msgList }) => { const lastTempMsg = msgList.at(-1) @@ -136,12 +136,12 @@ class Core extends Service { registerCallHook(NTMethod.DELETE_ACTIVE_CHAT, async (payload) => { const peerUid = payload[0] as string this.ctx.logger.info('激活的聊天窗口被删除,准备重新激活', peerUid) - let chatType = ChatType.friend + let chatType = ChatType.C2C if (isNumeric(peerUid)) { - chatType = ChatType.group + chatType = ChatType.Group } else if (!(await this.ctx.ntFriendApi.isBuddy(peerUid))) { - chatType = ChatType.temp + chatType = ChatType.TempC2CFromGroup } const peer = { peerUid, chatType } await this.ctx.sleep(1000) diff --git a/src/ntqqapi/entities.ts b/src/ntqqapi/entities.ts index 691bfab..ef0671b 100644 --- a/src/ntqqapi/entities.ts +++ b/src/ntqqapi/entities.ts @@ -28,11 +28,11 @@ import { isNullable } from 'cosmokit' export namespace SendElementEntities { export function text(content: string): SendTextElement { return { - elementType: ElementType.TEXT, + elementType: ElementType.Text, elementId: '', textElement: { content, - atType: AtType.notAt, + atType: AtType.Unknown, atUid: '', atTinyId: '', atNtUid: '', @@ -42,7 +42,7 @@ export namespace SendElementEntities { export function at(atUid: string, atNtUid: string, atType: AtType, display: string): SendTextElement { return { - elementType: ElementType.TEXT, + elementType: ElementType.Text, elementId: '', textElement: { content: display, @@ -56,7 +56,7 @@ export namespace SendElementEntities { export function reply(msgSeq: string, msgId: string, senderUin: string, senderUinStr: string): SendReplyElement { return { - elementType: ElementType.REPLY, + elementType: ElementType.Reply, elementId: '', replyElement: { replayMsgSeq: msgSeq, // raw.msgSeq @@ -68,7 +68,7 @@ export namespace SendElementEntities { } export async function pic(ctx: Context, picPath: string, summary = '', subType: 0 | 1 = 0, isFlashPic?: boolean): Promise { - const { md5, fileName, path, fileSize } = await ctx.ntFileApi.uploadFile(picPath, ElementType.PIC, subType) + const { md5, fileName, path, fileSize } = await ctx.ntFileApi.uploadFile(picPath, ElementType.Pic, subType) if (fileSize === 0) { throw '文件异常,大小为 0' } @@ -81,7 +81,7 @@ export namespace SendElementEntities { fileName: fileName, sourcePath: path, original: true, - picType: imageSize.type === 'gif' ? PicType.gif : PicType.jpg, + picType: imageSize.type === 'gif' ? PicType.GIF : PicType.JPEG, picSubType: subType, fileUuid: '', fileSubId: '', @@ -91,7 +91,7 @@ export namespace SendElementEntities { } ctx.logger.info('图片信息', picElement) return { - elementType: ElementType.PIC, + elementType: ElementType.Pic, elementId: '', picElement, } @@ -104,7 +104,7 @@ export namespace SendElementEntities { throw new Error('文件异常,大小为 0') } const element: SendFileElement = { - elementType: ElementType.FILE, + elementType: ElementType.File, elementId: '', fileElement: { fileName, @@ -123,7 +123,7 @@ export namespace SendElementEntities { throw `文件${filePath}异常,不存在` } ctx.logger.info('复制视频到QQ目录', filePath) - const { fileName: _fileName, path, fileSize, md5 } = await ctx.ntFileApi.uploadFile(filePath, ElementType.VIDEO) + const { fileName: _fileName, path, fileSize, md5 } = await ctx.ntFileApi.uploadFile(filePath, ElementType.Video) ctx.logger.info('复制视频到QQ目录完成', path) if (fileSize === 0) { @@ -200,7 +200,7 @@ export namespace SendElementEntities { thumbPath.set(0, _thumbPath) const thumbMd5 = await calculateFileMD5(_thumbPath) const element: SendVideoElement = { - elementType: ElementType.VIDEO, + elementType: ElementType.Video, elementId: '', videoElement: { fileName: fileName || _fileName, @@ -212,17 +212,7 @@ export namespace SendElementEntities { thumbSize, thumbWidth: videoInfo.width, thumbHeight: videoInfo.height, - fileSize: '' + fileSize, - // fileUuid: "", - // transferStatus: 0, - // progress: 0, - // invalidState: 0, - // fileSubId: "", - // fileBizId: null, - // originVideoMd5: "", - // fileFormat: 2, - // import_rich_media_context: null, - // sourceVideoCodecFormat: 2 + fileSize: String(fileSize), }, } ctx.logger.info('videoElement', element) @@ -235,7 +225,7 @@ export namespace SendElementEntities { throw '语音转换失败, 请检查语音文件是否正常' } // log("生成语音", silkPath, duration); - const { md5, fileName, path, fileSize } = await ctx.ntFileApi.uploadFile(silkPath, ElementType.PTT) + const { md5, fileName, path, fileSize } = await ctx.ntFileApi.uploadFile(silkPath, ElementType.Ptt) if (fileSize === 0) { throw '文件异常,大小为0' } @@ -243,14 +233,13 @@ export namespace SendElementEntities { unlink(silkPath) } return { - elementType: ElementType.PTT, + elementType: ElementType.Ptt, elementId: '', pttElement: { fileName: fileName, filePath: path, md5HexStr: md5, - fileSize: fileSize, - // duration: Math.max(1, Math.round(fileSize / 1024 / 3)), // 一秒钟大概是3kb大小, 小于1秒的按1秒算 + fileSize: String(fileSize), duration: duration, formatType: 1, voiceType: 1, @@ -279,7 +268,7 @@ export namespace SendElementEntities { faceType = 3; } return { - elementType: ElementType.FACE, + elementType: ElementType.Face, elementId: '', faceElement: { faceIndex: faceId, @@ -295,7 +284,8 @@ export namespace SendElementEntities { export function mface(emojiPackageId: number, emojiId: string, key: string, summary?: string): SendMarketFaceElement { return { - elementType: ElementType.MFACE, + elementType: ElementType.MarketFace, + elementId: '', marketFaceElement: { imageWidth: 300, imageHeight: 300, @@ -312,10 +302,10 @@ export namespace SendElementEntities { // 随机1到6 if (isNullable(resultId)) resultId = Math.floor(Math.random() * 6) + 1 return { - elementType: ElementType.FACE, + elementType: ElementType.Face, elementId: '', faceElement: { - faceIndex: FaceIndex.dice, + faceIndex: FaceIndex.Dice, faceType: 3, faceText: '[骰子]', packId: '1', @@ -334,7 +324,7 @@ export namespace SendElementEntities { // 实际测试并不能控制结果 if (isNullable(resultId)) resultId = Math.floor(Math.random() * 3) + 1 return { - elementType: ElementType.FACE, + elementType: ElementType.Face, elementId: '', faceElement: { faceIndex: FaceIndex.RPS, @@ -353,7 +343,7 @@ export namespace SendElementEntities { export function ark(data: string): SendArkElement { return { - elementType: ElementType.ARK, + elementType: ElementType.Ark, elementId: '', arkElement: { bytesData: data, @@ -365,7 +355,7 @@ export namespace SendElementEntities { export function shake(): SendFaceElement { return { - elementType: ElementType.FACE, + elementType: ElementType.Face, elementId: '', faceElement: { faceIndex: 1, diff --git a/src/ntqqapi/types/msg.ts b/src/ntqqapi/types/msg.ts index 0f7bd8d..46c10f3 100644 --- a/src/ntqqapi/types/msg.ts +++ b/src/ntqqapi/types/msg.ts @@ -1,126 +1,108 @@ import { GroupMemberRole } from './group' import { GeneralCallResult } from '../services' -export interface GetFileListParam { - sortType: number - fileCount: number - startIndex: number - sortOrder: number - showOnlinedocFolder: number - folderId?: string -} - export enum ElementType { - UNKNOWN = 0, - TEXT = 1, - PIC = 2, - FILE = 3, - PTT = 4, - VIDEO = 5, - FACE = 6, - REPLY = 7, - WALLET = 9, - GreyTip = 8, //Poke别叫戳一搓了 官方名字拍一拍 戳一戳是另一个名字 - ARK = 10, - MFACE = 11, - LIVEGIFT = 12, - STRUCTLONGMSG = 13, - MARKDOWN = 14, - GIPHY = 15, - MULTIFORWARD = 16, - INLINEKEYBOARD = 17, - INTEXTGIFT = 18, - CALENDAR = 19, - YOLOGAMERESULT = 20, - AVRECORD = 21, - FEED = 22, - TOFURECORD = 23, - ACEBUBBLE = 24, - ACTIVITY = 25, - TOFU = 26, - FACEBUBBLE = 27, - SHARELOCATION = 28, - TASKTOPMSG = 29, - RECOMMENDEDMSG = 43, - ACTIONBAR = 44 + Text = 1, + Pic = 2, + File = 3, + Ptt = 4, + Video = 5, + Face = 6, + Reply = 7, + GrayTip = 8, + Ark = 10, + MarketFace = 11, + LiveGift = 12, + StructLongMsg = 13, + Markdown = 14, + Giphy = 15, + MultiForward = 16, + InlineKeyboard = 17, + Calendar = 19, + YoloGameResult = 20, + AvRecord = 21, + TofuRecord = 23, + FaceBubble = 27, + ShareLocation = 28, + TaskTopMsg = 29, + RecommendedMsg = 43, + ActionBar = 44 } export interface SendTextElement { - elementType: ElementType.TEXT + elementType: ElementType.Text elementId: '' textElement: TextElement } export interface SendPttElement { - elementType: ElementType.PTT + elementType: ElementType.Ptt elementId: '' - pttElement: { - fileName: string - filePath: string - md5HexStr: string - fileSize: number - duration: number // 单位是秒 - formatType: number - voiceType: number - voiceChangeType: number - canConvert2Text: boolean - waveAmplitudes: number[] - fileSubId: '' - playState: number - autoConvertText: number - } -} - -export enum PicType { - gif = 2000, - jpg = 1000, -} - -export enum PicSubType { - normal = 0, // 普通图片,大图 - face = 1, // 表情包小图 + pttElement: Partial } export interface SendPicElement { - elementType: ElementType.PIC + elementType: ElementType.Pic elementId: '' - picElement: { - md5HexStr: string - fileSize: number | string - picWidth: number - picHeight: number - fileName: string - sourcePath: string - original: boolean - picType: PicType - picSubType: PicSubType - fileUuid: string - fileSubId: string - thumbFileSize: number - summary: string - } + picElement: Partial } export interface SendReplyElement { - elementType: ElementType.REPLY + elementType: ElementType.Reply elementId: '' replyElement: Partial } export interface SendFaceElement { - elementType: ElementType.FACE + elementType: ElementType.Face elementId: '' faceElement: FaceElement } export interface SendMarketFaceElement { - elementType: ElementType.MFACE + elementType: ElementType.MarketFace + elementId: '' marketFaceElement: MarketFaceElement } +export interface SendFileElement { + elementType: ElementType.File + elementId: '' + fileElement: FileElement +} + +export interface SendVideoElement { + elementType: ElementType.Video + elementId: '' + videoElement: VideoElement +} + +export interface SendArkElement { + elementType: ElementType.Ark + elementId: '' + arkElement: ArkElement +} + +export type SendMessageElement = + | SendTextElement + | SendPttElement + | SendPicElement + | SendReplyElement + | SendFaceElement + | SendMarketFaceElement + | SendFileElement + | SendVideoElement + | SendArkElement + +export enum AtType { + Unknown, + All, + One, +} + export interface TextElement { content: string - atType: number + atType: AtType atUid: string atTinyId: string atNtUid: string @@ -157,47 +139,6 @@ export interface FileElement { fileBizId?: number } -export interface SendFileElement { - elementType: ElementType.FILE - elementId: '' - fileElement: FileElement -} - -export interface SendVideoElement { - elementType: ElementType.VIDEO - elementId: '' - videoElement: VideoElement -} - -export interface SendArkElement { - elementType: ElementType.ARK - elementId: '' - arkElement: ArkElement -} - -export type SendMessageElement = - | SendTextElement - | SendPttElement - | SendPicElement - | SendReplyElement - | SendFaceElement - | SendMarketFaceElement - | SendFileElement - | SendVideoElement - | SendArkElement - -export enum AtType { - notAt = 0, - atAll = 1, - atUser = 2, -} - -export enum ChatType { - friend = 1, - group = 2, - temp = 100, -} - export interface PttElement { canConvert2Text: boolean duration: number // 秒数 @@ -208,7 +149,7 @@ export interface PttElement { fileSize: string // "4261" fileSubId: string // "0" fileUuid: string // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV" - formatType: string // 1 + formatType: number // 1 invalidState: number // 0 md5HexStr: string // "e4d09c784d5a2abcb2f9980bdc7acfe6" playState: number // 0 @@ -219,6 +160,7 @@ export interface PttElement { voiceChangeType: number // 0 voiceType: number // 0 waveAmplitudes: number[] + autoConvertText: number } export interface ArkElement { @@ -230,6 +172,16 @@ export interface ArkElement { export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn' export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn' +export enum PicType { + GIF = 2000, + JPEG = 1000, +} + +export enum PicSubType { + Normal = 0, // 普通图片,大图 + Face = 1, // 表情包小图 +} + export interface PicElement { picSubType: PicSubType picType: PicType // 有这玩意儿吗 @@ -246,22 +198,22 @@ export interface PicElement { } export enum GrayTipElementSubType { - REVOKE = 1, - PROCLAMATION = 2, - EMOJIREPLY = 3, - GROUP = 4, - BUDDY = 5, - FEED = 6, - ESSENCE = 7, - GROUPNOTIFY = 8, - BUDDYNOTIFY = 9, - FILE = 10, - FEEDCHANNELMSG = 11, - XMLMSG = 12, - LOCALMSG = 13, - BLOCK = 14, - AIOOP = 15, - WALLET = 16, + Revoke = 1, + Proclamation = 2, + EmojiReply = 3, + Group = 4, + Buddy = 5, + Feed = 6, + Essence = 7, + GroupNotify = 8, + BuddyNotify = 9, + File = 10, + FeedChannelMsg = 11, + XmlMsg = 12, + LocalMsg = 13, + Block = 14, + AioOp = 15, + Wallet = 16, JSON = 17, } @@ -291,7 +243,7 @@ export interface GrayTipElement { export enum FaceIndex { - dice = 358, + Dice = 358, RPS = 359, // 石头剪刀布 } @@ -365,6 +317,7 @@ export interface InlineKeyboardElementRowButton { enter: false subscribeDataTemplateIds: [] } + export interface InlineKeyboardElement { rows: [ { @@ -381,9 +334,9 @@ export interface TipAioOpGrayTipElement { } export enum TipGroupElementType { - memberIncrease = 1, - kicked = 3, // 被移出群 - ban = 8, + MemberIncrease = 1, + Kicked = 3, // 被移出群 + Ban = 8, } export interface TipGroupElement { @@ -425,17 +378,27 @@ export interface TipGroupElement { } } +export interface StructLongMsgElement { + xmlContent: string + resId: string +} + export interface MultiForwardMsgElement { xmlContent: string // xml格式的消息内容 resId: string fileName: string } +export enum ChatType { + C2C = 1, + Group = 2, + TempC2CFromGroup = 100, +} + export interface RawMessage { msgId: string msgType: number subMsgType: number - msgShortId?: number // 自己维护的消息id msgTime: string // 时间戳,秒 msgSeq: string msgRandom: string @@ -475,12 +438,11 @@ export interface MessageElement { fileElement?: FileElement liveGiftElement?: unknown markdownElement?: MarkdownElement - structLongMsgElement?: unknown + structLongMsgElement?: StructLongMsgElement multiForwardMsgElement?: MultiForwardMsgElement giphyElement?: unknown - walletElement?: unknown inlineKeyboardElement?: InlineKeyboardElement - textGiftElement?: unknown //???? + textGiftElement?: unknown calendarElement?: unknown yoloGameResultElement?: unknown avRecordElement?: unknown @@ -588,3 +550,12 @@ export interface TmpChatInfoApi extends GeneralCallResult { sig: string } } + +export interface GetFileListParam { + sortType: number + fileCount: number + startIndex: number + sortOrder: number + showOnlinedocFolder: number + folderId?: string +} diff --git a/src/onebot11/action/file/GetFile.ts b/src/onebot11/action/file/GetFile.ts index 18e8a10..36f544b 100644 --- a/src/onebot11/action/file/GetFile.ts +++ b/src/onebot11/action/file/GetFile.ts @@ -48,7 +48,7 @@ export abstract class GetFileBase extends BaseAction { const groupCode = payload.group_id.toString() const peer = { guildId: '', - chatType: ChatType.group, + chatType: ChatType.Group, peerUid: groupCode } const essence = await this.ctx.ntGroupApi.queryCachedEssenceMsg(groupCode) diff --git a/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts b/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts index 58750c7..90ca97a 100644 --- a/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts +++ b/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts @@ -28,7 +28,7 @@ export class GetGroupMsgHistory extends BaseAction { protected async _handle(payload: Payload): Promise { const { count, reverseOrder } = payload - const peer = { chatType: ChatType.group, peerUid: payload.group_id.toString() } + const peer = { chatType: ChatType.Group, peerUid: payload.group_id.toString() } let msgList: RawMessage[] if (!payload.message_seq || payload.message_seq === '0') { msgList = (await this.ctx.ntMsgApi.getAioFirstViewLatestMsgs(peer, +count)).msgList @@ -39,9 +39,6 @@ export class GetGroupMsgHistory extends BaseAction { } if (!msgList?.length) throw new Error('未找到消息') if (reverseOrder) msgList.reverse() - for (const msg of msgList) { - msg.msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId) - } const ob11MsgList = await Promise.all(msgList.map(msg => OB11Entities.message(this.ctx, msg))) return { messages: filterNullable(ob11MsgList) } } diff --git a/src/onebot11/action/go-cqhttp/SendForwardMsg.ts b/src/onebot11/action/go-cqhttp/SendForwardMsg.ts index f751eaa..14bd9af 100644 --- a/src/onebot11/action/go-cqhttp/SendForwardMsg.ts +++ b/src/onebot11/action/go-cqhttp/SendForwardMsg.ts @@ -36,8 +36,9 @@ export class SendForwardMsg extends BaseAction { contextMode = CreatePeerMode.Private } const peer = await createPeer(this.ctx, payload, contextMode) - const returnMsg = await this.handleForwardNode(peer, payload.messages) - return { message_id: returnMsg.msgShortId! } + const msg = await this.handleForwardNode(peer, payload.messages) + const msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId) + return { message_id: msgShortId } } private async cloneMsg(msg: RawMessage): Promise { @@ -52,7 +53,7 @@ export class SendForwardMsg extends BaseAction { this.ctx.logger.info('克隆消息', sendElements) try { const peer = { - chatType: ChatType.friend, + chatType: ChatType.C2C, peerUid: selfInfo.uid } const nodeMsg = await this.ctx.ntMsgApi.sendMsg(peer, sendElements) @@ -66,7 +67,7 @@ export class SendForwardMsg extends BaseAction { // 返回一个合并转发的消息id private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[]) { const selfPeer = { - chatType: ChatType.friend, + chatType: ChatType.C2C, peerUid: selfInfo.uid, } const nodeMsgIds: { msgId: string, peer: Peer }[] = [] @@ -100,7 +101,7 @@ export class SendForwardMsg extends BaseAction { sendElementsSplit[splitIndex] = [] } - if (ele.elementType === ElementType.FILE || ele.elementType === ElementType.VIDEO) { + if (ele.elementType === ElementType.File || ele.elementType === ElementType.Video) { if (sendElementsSplit[splitIndex].length > 0) { splitIndex++ } @@ -157,7 +158,6 @@ export class SendForwardMsg extends BaseAction { throw Error('转发消息失败,节点为空') } const returnMsg = await this.ctx.ntMsgApi.multiForwardMsg(srcPeer!, destPeer, retMsgIds) - returnMsg.msgShortId = this.ctx.store.createMsgShortId(destPeer, returnMsg.msgId) return returnMsg } } diff --git a/src/onebot11/action/llonebot/GetFriendMsgHistory.ts b/src/onebot11/action/llonebot/GetFriendMsgHistory.ts index 4f139ee..33b9045 100644 --- a/src/onebot11/action/llonebot/GetFriendMsgHistory.ts +++ b/src/onebot11/action/llonebot/GetFriendMsgHistory.ts @@ -38,14 +38,11 @@ export class GetFriendMsgHistory extends BaseAction { const uid = await this.ctx.ntUserApi.getUidByUin(payload.user_id.toString()) if (!uid) throw new Error(`记录${payload.user_id}不存在`) const isBuddy = await this.ctx.ntFriendApi.isBuddy(uid) - const peer = { chatType: isBuddy ? ChatType.friend : ChatType.temp, peerUid: uid } + const peer = { chatType: isBuddy ? ChatType.C2C : ChatType.TempC2CFromGroup, peerUid: uid } msgList = (await this.ctx.ntMsgApi.getAioFirstViewLatestMsgs(peer, +payload.count)).msgList } if (msgList.length === 0) throw new Error('未找到消息') if (payload.reverseOrder) msgList.reverse() - for (const msg of msgList) { - msg.msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId) - } const ob11MsgList = await Promise.all(msgList.map(msg => OB11Entities.message(this.ctx, msg))) return { messages: filterNullable(ob11MsgList) } } diff --git a/src/onebot11/action/msg/ForwardSingleMsg.ts b/src/onebot11/action/msg/ForwardSingleMsg.ts index ec77a93..18098c3 100644 --- a/src/onebot11/action/msg/ForwardSingleMsg.ts +++ b/src/onebot11/action/msg/ForwardSingleMsg.ts @@ -1,7 +1,6 @@ import { BaseAction } from '../BaseAction' -import { ChatType } from '@/ntqqapi/types' import { ActionName } from '../types' -import { Peer } from '@/ntqqapi/types' +import { createPeer } from '@/onebot11/helper/createMessage' interface Payload { message_id: number | string @@ -10,17 +9,6 @@ interface Payload { } abstract class ForwardSingleMsg extends BaseAction { - protected async getTargetPeer(payload: Payload): Promise { - if (payload.user_id) { - const peerUid = await this.ctx.ntUserApi.getUidByUin(payload.user_id.toString()) - if (!peerUid) { - throw new Error(`无法找到私聊对象${payload.user_id}`) - } - return { chatType: ChatType.friend, peerUid } - } - return { chatType: ChatType.group, peerUid: payload.group_id!.toString() } - } - protected async _handle(payload: Payload): Promise { if (!payload.message_id) { throw Error('message_id不能为空') @@ -29,7 +17,7 @@ abstract class ForwardSingleMsg extends BaseAction { if (!msg) { throw new Error(`无法找到消息${payload.message_id}`) } - const peer = await this.getTargetPeer(payload) + const peer = await createPeer(this.ctx, payload) const ret = await this.ctx.ntMsgApi.forwardMsg(msg.peer, peer, [msg.msgId]) if (ret.result !== 0) { throw new Error(`转发消息失败 ${ret.errMsg}`) diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 06ea824..7e76de3 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -93,7 +93,11 @@ export class SendMsg extends BaseAction { if (!returnMsg) { throw new Error('消息发送失败') } - return { message_id: returnMsg.msgShortId! } + const msgShortId = this.ctx.store.createMsgShortId({ + chatType: returnMsg.chatType, + peerUid: returnMsg.peerUid + }, returnMsg.msgId) + return { message_id: msgShortId } } private getSpecialMsgNum(message: OB11MessageData[], msgType: OB11MessageDataType): number { diff --git a/src/onebot11/adapter.ts b/src/onebot11/adapter.ts index ba28cfe..450621f 100644 --- a/src/onebot11/adapter.ts +++ b/src/onebot11/adapter.ts @@ -185,11 +185,6 @@ class OneBot11Adapter extends Service { if (parseInt(message.msgTime) < this.startTime / 1000) { continue } - const peer: Peer = { - chatType: message.chatType, - peerUid: message.peerUid - } - message.msgShortId = this.ctx.store.createMsgShortId(peer, message.msgId) this.addMsgCache(message) OB11Entities.message(this.ctx, message) diff --git a/src/onebot11/entities.ts b/src/onebot11/entities.ts index 303222b..fd21e12 100644 --- a/src/onebot11/entities.ts +++ b/src/onebot11/entities.ts @@ -53,14 +53,15 @@ export namespace OB11Entities { messagePostFormat, } = ctx.config as OneBot11Adapter.Config const selfUin = selfInfo.uin + const msgShortId = ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId) const resMsg: OB11Message = { self_id: parseInt(selfUin), user_id: parseInt(msg.senderUin), time: parseInt(msg.msgTime) || Date.now(), - message_id: msg.msgShortId!, - real_id: msg.msgShortId!, - message_seq: msg.msgShortId!, - message_type: msg.chatType === ChatType.group ? 'group' : 'private', + message_id: msgShortId, + real_id: msgShortId, + message_seq: msgShortId, + message_type: msg.chatType === ChatType.Group ? 'group' : 'private', sender: { user_id: parseInt(msg.senderUin), nickname: msg.sendNickName, @@ -76,7 +77,7 @@ export namespace OB11Entities { if (debug) { resMsg.raw = msg } - if (msg.chatType === ChatType.group) { + if (msg.chatType === ChatType.Group) { resMsg.sub_type = 'normal' resMsg.group_id = parseInt(msg.peerUin) const member = await ctx.ntGroupApi.getGroupMember(msg.peerUin, msg.senderUin) @@ -86,15 +87,15 @@ export namespace OB11Entities { resMsg.sender.title = member.memberSpecialTitle ?? '' } } - else if (msg.chatType === ChatType.friend) { + else if (msg.chatType === ChatType.C2C) { resMsg.sub_type = 'friend' resMsg.sender.nickname = (await ctx.ntUserApi.getUserDetailInfo(msg.senderUid)).nick } - else if (msg.chatType === ChatType.temp) { + else if (msg.chatType === ChatType.TempC2CFromGroup) { resMsg.sub_type = 'group' resMsg.temp_source = 0 //群聊 resMsg.sender.nickname = (await ctx.ntUserApi.getUserDetailInfo(msg.senderUid)).nick - const ret = await ctx.ntMsgApi.getTempChatInfo(ChatType.temp, msg.senderUid) + const ret = await ctx.ntMsgApi.getTempChatInfo(ChatType.TempC2CFromGroup, msg.senderUid) if (ret?.result === 0) { resMsg.sender.group_id = Number(ret.tmpChatInfo?.groupCode) } else { @@ -104,10 +105,10 @@ export namespace OB11Entities { for (const element of msg.elements) { let messageSegment: OB11MessageData | undefined - if (element.textElement && element.textElement?.atType !== AtType.notAt) { + if (element.textElement && element.textElement?.atType !== AtType.Unknown) { let qq: string let name: string | undefined - if (element.textElement.atType == AtType.atAll) { + if (element.textElement.atType === AtType.All) { qq = 'all' } else { const { atNtUid, atUid, content } = element.textElement @@ -291,7 +292,7 @@ export namespace OB11Entities { else if (element.faceElement) { const { faceElement } = element const faceId = faceElement.faceIndex - if (faceId === FaceIndex.dice) { + if (faceId === FaceIndex.Dice) { messageSegment = { type: OB11MessageDataType.dice, data: { @@ -368,7 +369,7 @@ export namespace OB11Entities { } export async function privateEvent(ctx: Context, msg: RawMessage): Promise { - if (msg.chatType !== ChatType.friend) { + if (msg.chatType !== ChatType.C2C) { return } for (const element of msg.elements) { @@ -397,7 +398,7 @@ export namespace OB11Entities { } export async function groupEvent(ctx: Context, msg: RawMessage): Promise { - if (msg.chatType !== ChatType.group) { + if (msg.chatType !== ChatType.Group) { return } if (msg.senderUin) { @@ -417,7 +418,7 @@ export namespace OB11Entities { const grayTipElement = element.grayTipElement const groupElement = grayTipElement?.groupElement if (groupElement) { - if (groupElement.type === TipGroupElementType.memberIncrease) { + if (groupElement.type === TipGroupElementType.MemberIncrease) { ctx.logger.info('收到群成员增加消息', groupElement) await ctx.sleep(1000) const member = await ctx.ntGroupApi.getGroupMember(msg.peerUid, groupElement.memberUid) @@ -431,7 +432,7 @@ export namespace OB11Entities { return new OB11GroupIncreaseEvent(parseInt(msg.peerUid), parseInt(memberUin), parseInt(operatorUin)) } } - else if (groupElement.type === TipGroupElementType.ban) { + else if (groupElement.type === TipGroupElementType.Ban) { ctx.logger.info('收到群群员禁言提示', groupElement) const memberUid = groupElement.shutUp?.member.uid const adminUid = groupElement.shutUp?.admin.uid @@ -461,7 +462,7 @@ export namespace OB11Entities { ) } } - else if (groupElement.type === TipGroupElementType.kicked) { + else if (groupElement.type === TipGroupElementType.Kicked) { ctx.logger.info(`收到我被踢出或退群提示, 群${msg.peerUid}`, groupElement) ctx.ntGroupApi.quitGroup(msg.peerUid) try { @@ -507,7 +508,7 @@ export namespace OB11Entities { const msgSeq: string = emojiLikeData.gtip.url.msgseq const emojiId: string = emojiLikeData.gtip.face.id const peer = { - chatType: ChatType.group, + chatType: ChatType.Group, guildId: '', peerUid: msg.peerUid, } @@ -531,7 +532,7 @@ export namespace OB11Entities { } if ( - grayTipElement.subElementType == GrayTipElementSubType.XMLMSG && + grayTipElement.subElementType == GrayTipElementSubType.XmlMsg && xmlElement?.templId == '10179' ) { ctx.logger.info('收到新人被邀请进群消息', grayTipElement) @@ -575,7 +576,7 @@ export namespace OB11Entities { if (!groupCode || !msgSeq || !msgRandom) return const peer = { guildId: '', - chatType: ChatType.group, + chatType: ChatType.Group, peerUid: groupCode } const essence = await ctx.ntGroupApi.queryCachedEssenceMsg(groupCode, msgSeq, msgRandom) @@ -611,13 +612,13 @@ export namespace OB11Entities { shortId: number ): Promise { const msgElement = msg.elements.find( - (element) => element.grayTipElement?.subElementType === GrayTipElementSubType.REVOKE, + (element) => element.grayTipElement?.subElementType === GrayTipElementSubType.Revoke, ) if (!msgElement) { return } const revokeElement = msgElement.grayTipElement!.revokeElement - if (msg.chatType === ChatType.group) { + if (msg.chatType === ChatType.Group) { const operator = await ctx.ntGroupApi.getGroupMember(msg.peerUid, revokeElement!.operatorUid) return new OB11GroupRecallNoticeEvent( parseInt(msg.peerUid), diff --git a/src/onebot11/helper/createMessage.ts b/src/onebot11/helper/createMessage.ts index 7d85ca9..4d5d2e2 100644 --- a/src/onebot11/helper/createMessage.ts +++ b/src/onebot11/helper/createMessage.ts @@ -62,22 +62,22 @@ export async function createSendElements( } } if (isAdmin && remainAtAllCount > 0) { - sendElements.push(SendElementEntities.at(atQQ, atQQ, AtType.atAll, '@全体成员')) + sendElements.push(SendElementEntities.at(atQQ, atQQ, AtType.All, '@全体成员')) } } - else if (peer.chatType === ChatType.group) { + else if (peer.chatType === ChatType.Group) { const atMember = await ctx.ntGroupApi.getGroupMember(peer.peerUid, atQQ) if (atMember) { const display = `@${atMember.cardName || atMember.nick}` sendElements.push( - SendElementEntities.at(atQQ, atMember.uid, AtType.atUser, display), + SendElementEntities.at(atQQ, atMember.uid, AtType.One, display), ) } else { const atNmae = sendMsg.data?.name const uid = await ctx.ntUserApi.getUidByUin(atQQ) || '' const display = atNmae ? `@${atNmae}` : '' sendElements.push( - SendElementEntities.at(atQQ, uid, AtType.atUser, display), + SendElementEntities.at(atQQ, uid, AtType.One, display), ) } } @@ -134,7 +134,7 @@ export async function createSendElements( sendMsg.data.subType || 0, sendMsg.data.type === 'flash' ) - deleteAfterSentFiles.push(res.picElement.sourcePath) + deleteAfterSentFiles.push(res.picElement.sourcePath!) sendElements.push(res) } break @@ -255,17 +255,17 @@ export async function sendMsg( let totalSize = 0 for (const fileElement of sendElements) { try { - if (fileElement.elementType === ElementType.PTT) { - totalSize += fs.statSync(fileElement.pttElement.filePath).size + if (fileElement.elementType === ElementType.Ptt) { + totalSize += fs.statSync(fileElement.pttElement.filePath!).size } - if (fileElement.elementType === ElementType.FILE) { + if (fileElement.elementType === ElementType.File) { totalSize += fs.statSync(fileElement.fileElement.filePath).size } - if (fileElement.elementType === ElementType.VIDEO) { + if (fileElement.elementType === ElementType.Video) { totalSize += fs.statSync(fileElement.videoElement.filePath).size } - if (fileElement.elementType === ElementType.PIC) { - totalSize += fs.statSync(fileElement.picElement.sourcePath).size + if (fileElement.elementType === ElementType.Pic) { + totalSize += fs.statSync(fileElement.picElement.sourcePath!).size } } catch (e) { ctx.logger.warn('文件大小计算失败', e, fileElement) @@ -276,8 +276,7 @@ export async function sendMsg( //log('设置消息超时时间', timeout) const returnMsg = await ctx.ntMsgApi.sendMsg(peer, sendElements, timeout) if (returnMsg) { - returnMsg.msgShortId = ctx.store.createMsgShortId(peer, returnMsg.msgId) - ctx.logger.info('消息发送', returnMsg.msgShortId) + ctx.logger.info('消息发送', peer) deleteAfterSentFiles.map(path => fsPromise.unlink(path)) return returnMsg } @@ -294,10 +293,10 @@ export enum CreatePeerMode { Group = 2 } -export async function createPeer(ctx: Context, payload: CreatePeerPayload, mode: CreatePeerMode): Promise { +export async function createPeer(ctx: Context, payload: CreatePeerPayload, mode = CreatePeerMode.Normal): Promise { if ((mode === CreatePeerMode.Group || mode === CreatePeerMode.Normal) && payload.group_id) { return { - chatType: ChatType.group, + chatType: ChatType.Group, peerUid: payload.group_id.toString(), } } @@ -306,7 +305,7 @@ export async function createPeer(ctx: Context, payload: CreatePeerPayload, mode: if (!uid) throw new Error('无法获取用户信息') const isBuddy = await ctx.ntFriendApi.isBuddy(uid) return { - chatType: isBuddy ? ChatType.friend : ChatType.temp, + chatType: isBuddy ? ChatType.C2C : ChatType.TempC2CFromGroup, peerUid: uid, } } From 1045c94a911fc2d38d69013ce0ffc907d76dd178 Mon Sep 17 00:00:00 2001 From: idranme Date: Wed, 25 Sep 2024 12:13:28 +0800 Subject: [PATCH 3/5] feat: `get_group_file_url` API --- src/ntqqapi/api/file.ts | 34 +++++++--- .../action/go-cqhttp/GetGroupFileUrl.ts | 64 +++++++++++++++++++ src/onebot11/action/index.ts | 2 + src/onebot11/action/types.ts | 3 +- 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/onebot11/action/go-cqhttp/GetGroupFileUrl.ts diff --git a/src/ntqqapi/api/file.ts b/src/ntqqapi/api/file.ts index 920f428..e1ecf4c 100644 --- a/src/ntqqapi/api/file.ts +++ b/src/ntqqapi/api/file.ts @@ -23,7 +23,6 @@ import { fileTypeFromFile } from 'file-type' import { copyFile, stat, unlink } from 'node:fs/promises' import { Time } from 'cosmokit' import { Service, Context } from 'cordis' -import { TEMP_DIR } from '@/common/globalVars' declare module 'cordis' { interface Context { @@ -107,8 +106,8 @@ export class NTQQFileApi extends Service { chatType: ChatType, peerUid: string, elementId: string, - thumbPath: string, - sourcePath: string, + thumbPath = '', + sourcePath = '', timeout = 1000 * 60 * 2, force = false ) { @@ -147,13 +146,7 @@ export class NTQQFileApi extends Service { timeout } ) - let filePath = data.notifyInfo.filePath - if (filePath.startsWith('\\')) { - const downloadPath = TEMP_DIR - filePath = path.join(downloadPath, filePath) - // 下载路径是下载文件夹的相对路径 - } - return filePath + return data.notifyInfo.filePath } async getImageSize(filePath: string) { @@ -201,6 +194,27 @@ export class NTQQFileApi extends Service { this.ctx.logger.error('图片url获取失败', element) return '' } + + async downloadFileForModelId(peer: Peer, fileModelId: string, timeout = 2 * Time.minute) { + const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>( + 'nodeIKernelRichMediaService/downloadFileForModelId', + [ + { + peer, + fileModelIdList: [fileModelId], + save_path: '' + }, + null, + ], + { + cbCmd: ReceiveCmdS.MEDIA_DOWNLOAD_COMPLETE, + cmdCB: payload => payload.notifyInfo.fileModelId === fileModelId, + timeout, + afterFirstCmd: false + } + ) + return data.notifyInfo.filePath + } } export class NTQQFileCacheApi extends Service { diff --git a/src/onebot11/action/go-cqhttp/GetGroupFileUrl.ts b/src/onebot11/action/go-cqhttp/GetGroupFileUrl.ts new file mode 100644 index 0000000..e868be4 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/GetGroupFileUrl.ts @@ -0,0 +1,64 @@ +import { BaseAction, Schema } from '../BaseAction' +import { ActionName } from '../types' +import { pathToFileURL } from 'node:url' +import { ChatType } from '@/ntqqapi/types' + +export interface Payload { + group_id: number | string + file_id: string + busid?: number +} + +export interface Response { + url: string +} + +export class GetGroupFileUrl extends BaseAction { + actionName = ActionName.GoCQHTTP_GetGroupFileUrl + payloadSchema = Schema.object({ + group_id: Schema.union([Number, String]).required(), + file_id: Schema.string().required() + }) + + protected async _handle(payload: Payload) { + const file = await this.ctx.store.getFileCacheById(payload.file_id) + if (file.length > 0) { + const { msgId, chatType, peerUid, elementId } = file[0] + const path = await this.ctx.ntFileApi.downloadMedia(msgId, chatType, peerUid, elementId) + return { + url: pathToFileURL(path).href + } + } else { + const groupId = payload.group_id.toString() + let modelId: string | undefined + let nextIndex: number | undefined + while (nextIndex !== 0) { + const res = await this.ctx.ntGroupApi.getGroupFileList(groupId, { + sortType: 1, + fileCount: 50, + startIndex: nextIndex ?? 0, + sortOrder: 2, + showOnlinedocFolder: 0, + }) + const file = res.item.find(item => item.fileInfo?.fileId === payload.file_id) + if (file) { + modelId = file.fileInfo?.fileModelId + break + } + nextIndex = res.nextIndex + } + if (modelId) { + const peer = { + chatType: ChatType.Group, + peerUid: groupId, + guildId: '' + } + const path = await this.ctx.ntFileApi.downloadFileForModelId(peer, modelId) + return { + url: pathToFileURL(path).href + } + } + throw new Error('file not found') + } + } +} diff --git a/src/onebot11/action/index.ts b/src/onebot11/action/index.ts index 082ae58..d037dfe 100644 --- a/src/onebot11/action/index.ts +++ b/src/onebot11/action/index.ts @@ -69,6 +69,7 @@ import { GetGroupFilesByFolder } from './go-cqhttp/GetGroupFilesByFolder' import { GetFriendWithCategory } from './llonebot/GetFriendWithCategory' import { UploadGroupFile } from './go-cqhttp/UploadGroupFile' import { UploadPrivateFile } from './go-cqhttp/UploadPrivateFile' +import { GetGroupFileUrl } from './go-cqhttp/GetGroupFileUrl' export function initActionMap(adapter: Adapter) { const actionHandlers = [ @@ -143,6 +144,7 @@ export function initActionMap(adapter: Adapter) { new GetGroupRootFiles(adapter), new SendGroupNotice(adapter), new GetGroupFilesByFolder(adapter), + new GetGroupFileUrl(adapter) ] const actionMap = new Map>() for (const action of actionHandlers) { diff --git a/src/onebot11/action/types.ts b/src/onebot11/action/types.ts index b7de695..d48b780 100644 --- a/src/onebot11/action/types.ts +++ b/src/onebot11/action/types.ts @@ -81,5 +81,6 @@ export enum ActionName { GoCQHTTP_GetGroupAtAllRemain = 'get_group_at_all_remain', GoCQHTTP_GetGroupRootFiles = 'get_group_root_files', GoCQHTTP_SendGroupNotice = '_send_group_notice', - GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder' + GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder', + GoCQHTTP_GetGroupFileUrl = 'get_group_file_url' } From 517b2334962ec99d274b2a3c3be25b44033ef107 Mon Sep 17 00:00:00 2001 From: idranme Date: Wed, 25 Sep 2024 12:14:06 +0800 Subject: [PATCH 4/5] fix --- src/onebot11/action/user/SetFriendAddRequest.ts | 6 ++++++ src/onebot11/entities.ts | 17 ++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/onebot11/action/user/SetFriendAddRequest.ts b/src/onebot11/action/user/SetFriendAddRequest.ts index c87ee76..864d4d5 100644 --- a/src/onebot11/action/user/SetFriendAddRequest.ts +++ b/src/onebot11/action/user/SetFriendAddRequest.ts @@ -1,5 +1,6 @@ import { BaseAction } from '../BaseAction' import { ActionName } from '../types' +import { ChatType } from '@/ntqqapi/types' interface Payload { flag: string @@ -22,6 +23,11 @@ export default class SetFriendAddRequest extends BaseAction { if (payload.remark) { await this.ctx.ntFriendApi.setBuddyRemark(uid, payload.remark) } + await this.ctx.ntMsgApi.activateChat({ + peerUid: uid, + chatType: ChatType.C2C, + guildId: '' + }) return null } } diff --git a/src/onebot11/entities.ts b/src/onebot11/entities.ts index fd21e12..fa99b1e 100644 --- a/src/onebot11/entities.ts +++ b/src/onebot11/entities.ts @@ -291,28 +291,31 @@ export namespace OB11Entities { } else if (element.faceElement) { const { faceElement } = element - const faceId = faceElement.faceIndex - if (faceId === FaceIndex.Dice) { + const { faceIndex, pokeType } = faceElement + if (faceIndex === FaceIndex.Dice) { messageSegment = { type: OB11MessageDataType.dice, data: { result: faceElement.resultId! } } - } - else if (faceId === FaceIndex.RPS) { + } else if (faceIndex === FaceIndex.RPS) { messageSegment = { type: OB11MessageDataType.RPS, data: { result: faceElement.resultId! } } - } - else { + /*} else if (faceIndex === 1 && pokeType === 1) { + messageSegment = { + type: OB11MessageDataType.shake, + data: {} + }*/ + } else { messageSegment = { type: OB11MessageDataType.face, data: { - id: faceId.toString() + id: faceIndex.toString() } } } From fd478cdaedcb59b557191e7a15329b04a6d12ef5 Mon Sep 17 00:00:00 2001 From: idranme Date: Wed, 25 Sep 2024 14:55:05 +0800 Subject: [PATCH 5/5] chore: v3.33.7 --- manifest.json | 2 +- src/version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index 23ee0f1..bf7e544 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "LLOneBot", "slug": "LLOneBot", "description": "实现 OneBot 11 协议,用于 QQ 机器人开发", - "version": "3.33.6", + "version": "3.33.7", "icon": "./icon.webp", "authors": [ { diff --git a/src/version.ts b/src/version.ts index c482c47..16447d1 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '3.33.6' +export const version = '3.33.7'