Compare commits

..

17 Commits

Author SHA1 Message Date
idranme
4bf79e021e Merge pull request #383 from LLOneBot/dev
3.31.3
2024-09-01 00:36:41 +08:00
idranme
2dac109e58 chore: v3.31.3 2024-09-01 00:34:08 +08:00
idranme
2637a5da6d chore 2024-08-31 22:59:42 +08:00
idranme
f8b2be246f optimize 2024-08-31 22:55:26 +08:00
idranme
44921e85ad chore 2024-08-31 19:46:35 +08:00
idranme
388e016365 optimize 2024-08-31 19:41:48 +08:00
idranme
a2056a43f3 fix 2024-08-31 01:29:44 +08:00
idranme
a249e0b581 Merge pull request #381 from LLOneBot/dev
3.31.2
2024-08-30 12:47:18 +08:00
idranme
f7343332d7 chore: v3.31.2 2024-08-30 12:46:03 +08:00
idranme
bf17d46157 fix 2024-08-30 12:38:39 +08:00
idranme
3e3f792035 optimize 2024-08-30 03:09:34 +08:00
idranme
d7cc5d68a7 refactor 2024-08-30 02:52:21 +08:00
idranme
64a8efb8df optimize 2024-08-30 02:51:56 +08:00
idranme
6af31c48c4 fix 2024-08-29 20:48:08 +08:00
idranme
6954551cb7 feat 2024-08-29 18:06:53 +08:00
idranme
c71885a29e refactor 2024-08-28 23:57:11 +08:00
idranme
183eab2cf4 optimize 2024-08-28 17:13:26 +08:00
43 changed files with 692 additions and 856 deletions

View File

@@ -4,7 +4,7 @@
"name": "LLOneBot",
"slug": "LLOneBot",
"description": "实现 OneBot 11 协议,用于 QQ 机器人开发",
"version": "3.31.1",
"version": "3.31.3",
"icon": "./icon.webp",
"authors": [
{

View File

@@ -82,7 +82,7 @@ class MessageUniqueWrapper {
return ret.map((t) => t?.MsgId).filter((t) => t !== undefined)
}
createMsg(peer: Peer, msgId: string): number | undefined {
createMsg(peer: Peer, msgId: string): number {
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`
const hash = createHash('md5').update(key).digest()
//设置第一个bit为0 保证shortId为正数

5
src/global.d.ts vendored
View File

@@ -2,9 +2,6 @@ import type { LLOneBot } from './preload'
import { Dict } from 'cosmokit'
declare global {
interface Window {
llonebot: LLOneBot
LiteLoader: Dict
}
var llonebot: LLOneBot
var LiteLoader: Dict
}

View File

@@ -18,18 +18,15 @@ export default class Log {
return
}
const file = path.join(LOG_DIR, cfg.filename)
const refreshNick = ctx.debounce(() => {
/*const refreshNick = ctx.debounce(() => {
const ntUserApi = ctx.get('ntUserApi')
if (ntUserApi && !selfInfo.nick) {
ntUserApi.getSelfNick(true)
}
}, 1000)
}, 1000)*/
const target: Logger.Target = {
colors: 0,
record: (record: Logger.Record) => {
if (!selfInfo.nick) {
refreshNick()
}
const dateTime = new Date(record.timestamp).toLocaleString()
const userInfo = selfInfo.uin ? `${selfInfo.nick}(${selfInfo.uin})` : ''
const content = `${dateTime} [${record.type}] ${userInfo} | ${record.name} ${record.content}\n\n`

View File

@@ -199,14 +199,16 @@ function onLoad() {
// 创建窗口时触发
function onBrowserWindowCreated(window: BrowserWindow) {
if (window.id !== 2) {
if (![2, 4].includes(window.id)) {
return
}
mainWindow = window
log('window create', window.webContents.getURL().toString())
if (window.id === 2) {
mainWindow = window
}
//log('window create', window.webContents.getURL().toString())
try {
hookNTQQApiCall(window)
hookNTQQApiReceive(window)
hookNTQQApiCall(window, window.id !== 2)
hookNTQQApiReceive(window, window.id !== 2)
} catch (e: any) {
log('LLOneBot hook error: ', e.toString())
}

View File

@@ -5,7 +5,6 @@ import {
CacheFileListItem,
CacheFileType,
CacheScanResult,
ChatCacheList,
ChatCacheListItemBasic,
ChatType,
ElementType,
@@ -43,14 +42,32 @@ export class NTQQFileApi extends Service {
this.rkeyManager = new RkeyManager(ctx, 'http://napcat-sign.wumiao.wang:2082/rkey')
}
/** 27187 TODO */
async getVideoUrl(peer: Peer, msgId: string, elementId: string) {
const session = getSession()
return (await session?.getRichMediaService().getVideoPlayUrlV2(peer,
msgId,
elementId,
0,
{ downSourceType: 1, triggerType: 1 }))?.urlResult.domainUrl[0].url
if (session) {
return (await session.getRichMediaService().getVideoPlayUrlV2(
peer,
msgId,
elementId,
0,
{ downSourceType: 1, triggerType: 1 }
)).urlResult.domainUrl[0]?.url
} else {
const data = await invoke('nodeIKernelRichMediaService/getVideoPlayUrlV2', [{
peer,
msgId,
elemId: elementId,
videoCodecFormat: 0,
exParams: {
downSourceType: 1,
triggerType: 1
},
}, null])
if (data.result !== 0) {
this.ctx.logger.warn('getVideoUrl', data)
}
return data.urlResult.domainUrl[0]?.url
}
}
async getFileType(filePath: string) {
@@ -82,23 +99,18 @@ export class NTQQFileApi extends Service {
file_uuid: ''
})
} else {
mediaPath = await invoke<string>({
methodName: NTMethod.MEDIA_FILE_PATH,
args: [
{
path_info: {
md5HexStr: fileMd5,
fileName: fileName,
elementType: elementType,
elementSubType,
thumbSize: 0,
needCreate: true,
downloadType: 1,
file_uuid: '',
},
},
],
})
mediaPath = await invoke(NTMethod.MEDIA_FILE_PATH, [{
path_info: {
md5HexStr: fileMd5,
fileName: fileName,
elementType: elementType,
elementSubType,
thumbSize: 0,
needCreate: true,
downloadType: 1,
file_uuid: '',
},
}])
}
await fsPromise.copyFile(filePath, mediaPath)
const fileSize = (await fsPromise.stat(filePath)).size
@@ -174,9 +186,9 @@ export class NTQQFileApi extends Service {
)
filePath = data[1].filePath
} else {
const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>({
methodName: NTMethod.DOWNLOAD_MEDIA,
args: [
const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>(
NTMethod.DOWNLOAD_MEDIA,
[
{
getReq: {
fileModelId: '0',
@@ -193,10 +205,12 @@ export class NTQQFileApi extends Service {
},
null,
],
cbCmd: ReceiveCmdS.MEDIA_DOWNLOAD_COMPLETE,
cmdCB: payload => payload.notifyInfo.msgId === msgId,
timeout
})
{
cbCmd: ReceiveCmdS.MEDIA_DOWNLOAD_COMPLETE,
cmdCB: payload => payload.notifyInfo.msgId === msgId,
timeout
}
)
filePath = data.notifyInfo.filePath
}
if (filePath.startsWith('\\')) {
@@ -208,11 +222,13 @@ export class NTQQFileApi extends Service {
}
async getImageSize(filePath: string) {
return await invoke<{ width: number; height: number }>({
className: NTClass.FS_API,
methodName: NTMethod.IMAGE_SIZE,
args: [filePath],
})
return await invoke<{ width: number; height: number }>(
NTMethod.IMAGE_SIZE,
[filePath],
{
className: NTClass.FS_API,
}
)
}
async getImageUrl(element: PicElement) {
@@ -254,15 +270,7 @@ export class NTQQFileCacheApi extends Service {
}
async setCacheSilentScan(isSilent: boolean = true) {
return await invoke<GeneralCallResult>({
methodName: NTMethod.CACHE_SET_SILENCE,
args: [
{
isSilent,
},
null,
],
})
return await invoke<GeneralCallResult>(NTMethod.CACHE_SET_SILENCE, [{ isSilent }, null])
}
getCacheSessionPathList() {
@@ -271,110 +279,38 @@ export class NTQQFileCacheApi extends Service {
key: string
value: string
}[]
>({
className: NTClass.OS_API,
methodName: NTMethod.CACHE_PATH_SESSION,
})
}
clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
return invoke<any>({
// TODO: 目前还不知道真正的返回值是什么
methodName: NTMethod.CACHE_CLEAR,
args: [
{
keys: cacheKeys,
},
null,
],
})
}
addCacheScannedPaths(pathMap: object = {}) {
return invoke<GeneralCallResult>({
methodName: NTMethod.CACHE_ADD_SCANNED_PATH,
args: [
{
pathMap: { ...pathMap },
},
null,
],
})
>(NTMethod.CACHE_PATH_SESSION, [], { className: NTClass.OS_API })
}
scanCache() {
invoke<GeneralCallResult>({
methodName: ReceiveCmdS.CACHE_SCAN_FINISH,
classNameIsRegister: true,
}).then()
return invoke<CacheScanResult>({
methodName: NTMethod.CACHE_SCAN,
args: [null, null],
timeout: 300 * Time.second,
})
invoke<GeneralCallResult>(ReceiveCmdS.CACHE_SCAN_FINISH, [], { classNameIsRegister: true })
return invoke<CacheScanResult>(NTMethod.CACHE_SCAN, [null, null], { timeout: 300 * Time.second })
}
getHotUpdateCachePath() {
return invoke<string>({
className: NTClass.HOTUPDATE_API,
methodName: NTMethod.CACHE_PATH_HOT_UPDATE,
})
return invoke<string>(NTMethod.CACHE_PATH_HOT_UPDATE, [], { className: NTClass.HOTUPDATE_API })
}
getDesktopTmpPath() {
return invoke<string>({
className: NTClass.BUSINESS_API,
methodName: NTMethod.CACHE_PATH_DESKTOP_TEMP,
})
}
getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) {
return new Promise<ChatCacheList>((res, rej) => {
invoke<ChatCacheList>({
methodName: NTMethod.CACHE_CHAT_GET,
args: [
{
chatType: type,
pageSize,
order: 1,
pageIndex,
},
null,
],
})
.then((list) => res(list))
.catch((e) => rej(e))
})
return invoke<string>(NTMethod.CACHE_PATH_DESKTOP_TEMP, [], { className: NTClass.BUSINESS_API })
}
getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
const _lastRecord = lastRecord ? lastRecord : { fileType: fileType }
return invoke<CacheFileList>({
methodName: NTMethod.CACHE_FILE_GET,
args: [
{
fileType: fileType,
restart: true,
pageSize: pageSize,
order: 1,
lastRecord: _lastRecord,
},
null,
],
})
return invoke<CacheFileList>(NTMethod.CACHE_FILE_GET, [{
fileType: fileType,
restart: true,
pageSize: pageSize,
order: 1,
lastRecord: _lastRecord,
}, null])
}
async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {
return await invoke<GeneralCallResult>({
methodName: NTMethod.CACHE_CHAT_CLEAR,
args: [
{
chats,
fileKeys,
},
null,
],
})
return await invoke<GeneralCallResult>(NTMethod.CACHE_CHAT_CLEAR, [{
chats,
fileKeys,
}, null])
}
}

View File

@@ -4,7 +4,6 @@ import { invoke, NTMethod, NTClass } from '../ntcall'
import { getSession } from '@/ntqqapi/wrapper'
import { BuddyListReqType, NodeIKernelProfileService } from '../services'
import { NTEventDispatch } from '@/common/utils/eventTask'
import { LimitedHashTable } from '@/common/utils/table'
import { pick } from 'cosmokit'
import { Service, Context } from 'cordis'
@@ -28,12 +27,15 @@ export class NTQQFriendApi extends Service {
categroyMbCount: number
buddyList: Friend[]
}[]
}>({
className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList',
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
})
}>(
'getBuddyList',
[],
{
className: NTClass.NODE_STORE_API,
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
}
)
const _friends: Friend[] = []
for (const item of data.data) {
_friends.push(...item.buddyList)
@@ -56,18 +58,13 @@ export class NTQQFriendApi extends Service {
accept
})
} else {
return await invoke({
methodName: NTMethod.HANDLE_FRIEND_REQUEST,
args: [
{
approvalInfo: {
friendUid,
reqTime,
accept,
},
},
],
})
return await invoke(NTMethod.HANDLE_FRIEND_REQUEST, [{
approvalInfo: {
friendUid,
reqTime,
accept,
},
}])
}
}
@@ -86,13 +83,15 @@ export class NTQQFriendApi extends Service {
const data = await invoke<{
buddyCategory: CategoryFriend[]
userSimpleInfos: Record<string, SimpleInfo>
}>({
className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList',
args: [refresh],
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
})
}>(
'getBuddyList',
[refresh],
{
className: NTClass.NODE_STORE_API,
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
}
)
const categoryUids: Map<number, string[]> = new Map()
for (const item of data.buddyCategory) {
categoryUids.set(item.categoryId, item.buddyUids)
@@ -101,8 +100,9 @@ export class NTQQFriendApi extends Service {
}
}
async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> {
const retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000)
/** uid => uin */
async getBuddyIdMap(refresh = false): Promise<Map<string, string>> {
const retMap: Map<string, string> = new Map()
const session = getSession()
if (session) {
const uids: string[] = []
@@ -112,22 +112,30 @@ export class NTQQFriendApi extends Service {
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
)
data.forEach((value, key) => {
retMap.set(value.uin!, value.uid!)
})
for (const [, item] of data) {
if (retMap.size > 5000) {
break
}
retMap.set(item.uid!, item.uin!)
}
} else {
const data = await invoke<{
buddyCategory: CategoryFriend[]
userSimpleInfos: Record<string, SimpleInfo>
}>({
className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList',
args: [refresh],
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
})
}>(
'getBuddyList',
[refresh],
{
className: NTClass.NODE_STORE_API,
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
}
)
for (const item of Object.values(data.userSimpleInfos)) {
retMap.set(item.uin!, item.uid!)
if (retMap.size > 5000) {
break
}
retMap.set(item.uid!, item.uin!)
}
}
return retMap
@@ -158,13 +166,15 @@ export class NTQQFriendApi extends Service {
const data = await invoke<{
buddyCategory: CategoryFriend[]
userSimpleInfos: Record<string, SimpleInfo>
}>({
className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList',
args: [refresh],
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
})
}>(
'getBuddyList',
[refresh],
{
className: NTClass.NODE_STORE_API,
cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false,
}
)
const category: Map<number, Pick<CategoryFriend, 'buddyUids' | 'categroyName'>> = new Map()
for (const item of data.buddyCategory) {
category.set(item.categoryId, pick(item, ['buddyUids', 'categroyName']))
@@ -186,13 +196,7 @@ export class NTQQFriendApi extends Service {
if (session) {
return session.getBuddyService().isBuddy(uid)
} else {
return await invoke<boolean>({
methodName: 'nodeIKernelBuddyService/isBuddy',
args: [
{ uid },
null,
],
})
return await invoke('nodeIKernelBuddyService/isBuddy', [{ uid }, null])
}
}
}

View File

@@ -17,6 +17,8 @@ declare module 'cordis' {
}
export class NTQQGroupApi extends Service {
static inject = ['ntWindowApi']
private groupMembers: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>()
constructor(protected ctx: Context) {
@@ -41,45 +43,29 @@ export class NTQQGroupApi extends Service {
const result = await invoke<{
updateType: number
groupList: Group[]
}>({
className: NTClass.NODE_STORE_API,
methodName: 'getGroupList',
cbCmd: ReceiveCmdS.GROUPS_STORE,
afterFirstCmd: false,
})
}>(
'getGroupList',
[],
{
className: NTClass.NODE_STORE_API,
cbCmd: ReceiveCmdS.GROUPS_STORE,
afterFirstCmd: false,
}
)
return result.groupList
}
}
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
async getGroupMembers(groupCode: string, num = 3000): Promise<Map<string, GroupMember>> {
const session = getSession()
let result: Awaited<ReturnType<NodeIKernelGroupService['getNextMemberList']>>
if (session) {
const groupService = session.getGroupService()
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow')
const sceneId = groupService.createMemberListScene(groupCode, 'groupMemberList_MainWindow')
result = await groupService.getNextMemberList(sceneId, undefined, num)
} else {
const sceneId = await invoke<string>({
methodName: NTMethod.GROUP_MEMBER_SCENE,
args: [
{
groupCode: groupQQ,
scene: 'groupMemberList_MainWindow',
},
],
})
result = await invoke<
ReturnType<NodeIKernelGroupService['getNextMemberList']>
>({
methodName: NTMethod.GROUP_MEMBERS,
args: [
{
sceneId,
num,
},
null,
],
})
const sceneId = await invoke(NTMethod.GROUP_MEMBER_SCENE, [{ groupCode, scene: 'groupMemberList_MainWindow' }])
result = await invoke(NTMethod.GROUP_MEMBERS, [{ sceneId, num }, null])
}
if (result.errCode !== 0) {
throw ('获取群成员列表出错,' + result.errMsg)
@@ -144,23 +130,17 @@ export class NTQQGroupApi extends Service {
)
return notifies
} else {
invoke({
methodName: ReceiveCmdS.GROUP_NOTIFY,
classNameIsRegister: true,
})
return (await invoke<GroupNotifies>({
methodName: NTMethod.GET_GROUP_NOTICE,
cbCmd: ReceiveCmdS.GROUP_NOTIFY,
afterFirstCmd: false,
args: [{ doubt: false, startSeq: '', number: num }, null],
})).notifies
}
}
invoke(ReceiveCmdS.GROUP_NOTIFY, [], { classNameIsRegister: true })
return (await invoke<GroupNotifies>(
NTMethod.GET_GROUP_NOTICE,
[{ doubt: false, startSeq: '', number: num }, null],
{
/** 27187 TODO */
async delGroupFile(groupCode: string, files: string[]) {
const session = getSession()
return session?.getRichMediaService().deleteGroupFile(groupCode, [102], files)
cbCmd: ReceiveCmdS.GROUP_NOTIFY,
afterFirstCmd: false,
}
)).notifies
}
}
async handleGroupRequest(flag: string, operateType: GroupRequestOperateTypes, reason?: string) {
@@ -182,152 +162,87 @@ export class NTQQGroupApi extends Service {
}
})
} else {
return await invoke({
methodName: NTMethod.HANDLE_GROUP_REQUEST,
args: [
{
doubt: false,
operateMsg: {
operateType,
targetMsg: {
seq,
type,
groupCode,
postscript: reason || ' ' // 仅传空值可能导致处理失败,故默认给个空格
},
},
return await invoke(NTMethod.HANDLE_GROUP_REQUEST, [{
doubt: false,
operateMsg: {
operateType,
targetMsg: {
seq,
type,
groupCode,
postscript: reason || ' ' // 仅传空值可能导致处理失败,故默认给个空格
},
null,
],
})
},
}, null])
}
}
async quitGroup(groupQQ: string) {
async quitGroup(groupCode: string) {
const session = getSession()
if (session) {
return session.getGroupService().quitGroup(groupQQ)
return session.getGroupService().quitGroup(groupCode)
} else {
return await invoke({
methodName: NTMethod.QUIT_GROUP,
args: [{ groupCode: groupQQ }, null],
})
return await invoke(NTMethod.QUIT_GROUP, [{ groupCode }, null])
}
}
async kickMember(
groupQQ: string,
groupCode: string,
kickUids: string[],
refuseForever = false,
kickReason = '',
) {
const session = getSession()
if (session) {
return session.getGroupService().kickMember(groupQQ, kickUids, refuseForever, kickReason)
return session.getGroupService().kickMember(groupCode, kickUids, refuseForever, kickReason)
} else {
return await invoke({
methodName: NTMethod.KICK_MEMBER,
args: [
{
groupCode: groupQQ,
kickUids,
refuseForever,
kickReason,
},
],
})
return await invoke(NTMethod.KICK_MEMBER, [{ groupCode, kickUids, refuseForever, kickReason }])
}
}
async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
async banMember(groupCode: string, memList: Array<{ uid: string, timeStamp: number }>) {
// timeStamp为秒数, 0为解除禁言
const session = getSession()
if (session) {
return session.getGroupService().setMemberShutUp(groupQQ, memList)
return session.getGroupService().setMemberShutUp(groupCode, memList)
} else {
return await invoke({
methodName: NTMethod.MUTE_MEMBER,
args: [
{
groupCode: groupQQ,
memList,
},
],
})
return await invoke(NTMethod.MUTE_MEMBER, [{ groupCode, memList }])
}
}
async banGroup(groupQQ: string, shutUp: boolean) {
async banGroup(groupCode: string, shutUp: boolean) {
const session = getSession()
if (session) {
return session.getGroupService().setGroupShutUp(groupQQ, shutUp)
return session.getGroupService().setGroupShutUp(groupCode, shutUp)
} else {
return await invoke({
methodName: NTMethod.MUTE_GROUP,
args: [
{
groupCode: groupQQ,
shutUp,
},
null,
],
})
return await invoke(NTMethod.MUTE_GROUP, [{ groupCode, shutUp }, null])
}
}
async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
async setMemberCard(groupCode: string, memberUid: string, cardName: string) {
const session = getSession()
if (session) {
return session.getGroupService().modifyMemberCardName(groupQQ, memberUid, cardName)
return session.getGroupService().modifyMemberCardName(groupCode, memberUid, cardName)
} else {
return await invoke({
methodName: NTMethod.SET_MEMBER_CARD,
args: [
{
groupCode: groupQQ,
uid: memberUid,
cardName,
},
null,
],
})
return await invoke(NTMethod.SET_MEMBER_CARD, [{ groupCode, uid: memberUid, cardName }, null])
}
}
async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
async setMemberRole(groupCode: string, memberUid: string, role: GroupMemberRole) {
const session = getSession()
if (session) {
return session.getGroupService().modifyMemberRole(groupQQ, memberUid, role)
return session.getGroupService().modifyMemberRole(groupCode, memberUid, role)
} else {
return await invoke({
methodName: NTMethod.SET_MEMBER_ROLE,
args: [
{
groupCode: groupQQ,
uid: memberUid,
role,
},
null,
],
})
return await invoke(NTMethod.SET_MEMBER_ROLE, [{ groupCode, uid: memberUid, role }, null])
}
}
async setGroupName(groupQQ: string, groupName: string) {
async setGroupName(groupCode: string, groupName: string) {
const session = getSession()
if (session) {
return session.getGroupService().modifyGroupName(groupQQ, groupName, false)
return session.getGroupService().modifyGroupName(groupCode, groupName, false)
} else {
return await invoke({
methodName: NTMethod.SET_GROUP_NAME,
args: [
{
groupCode: groupQQ,
groupName,
},
null,
],
})
return await invoke(NTMethod.SET_GROUP_NAME, [{ groupCode, groupName }, null])
}
}
@@ -342,15 +257,7 @@ export class NTQQGroupApi extends Service {
canNotAtAllMsg: ''
}
}
>({
methodName: NTMethod.GROUP_AT_ALL_REMAIN_COUNT,
args: [
{
groupCode,
},
null,
],
})
>(NTMethod.GROUP_AT_ALL_REMAIN_COUNT, [{ groupCode }, null])
}
/** 27187 TODO */
@@ -382,4 +289,16 @@ export class NTQQGroupApi extends Service {
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
return session?.getGroupService().addGroupEssence(param)
}
async createGroupFileFolder(groupId: string, folderName: string) {
return await invoke('nodeIKernelRichMediaService/createGroupFolder', [{ groupId, folderName }, null])
}
async deleteGroupFileFolder(groupId: string, folderId: string) {
return await invoke('nodeIKernelRichMediaService/deleteGroupFolder', [{ groupId, folderId }, null])
}
async deleteGroupFile(groupId: string, fileIdList: string[]) {
return await invoke('nodeIKernelRichMediaService/deleteGroupFile', [{ groupId, busIdList: [102], fileIdList }, null])
}
}

View File

@@ -1,5 +1,5 @@
import { invoke, NTMethod } from '../ntcall'
import { GeneralCallResult, TmpChatInfoApi } from '../services'
import { GeneralCallResult } from '../services'
import { RawMessage, SendMessageElement, Peer, ChatType2 } from '../types'
import { getSession } from '@/ntqqapi/wrapper'
import { NTEventDispatch } from '@/common/utils/eventTask'
@@ -23,6 +23,8 @@ function generateMsgId() {
}
export class NTQQMsgApi extends Service {
static inject = ['ntUserApi']
constructor(protected ctx: Context) {
super(ctx, 'ntMsgApi', true)
}
@@ -32,41 +34,20 @@ export class NTQQMsgApi extends Service {
if (session) {
return session.getMsgService().getTempChatInfo(chatType, peerUid)
} else {
return await invoke<TmpChatInfoApi>({
methodName: 'nodeIKernelMsgService/getTempChatInfo',
args: [
{
chatType,
peerUid,
},
null,
],
})
return await invoke('nodeIKernelMsgService/getTempChatInfo', [{ chatType, peerUid }, null])
}
}
async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set: boolean = true) {
async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, setEmoji: boolean = true) {
// nt_qq//global//nt_data//Emoji//emoji-resource//sysface_res/apng/ 下可以看到所有QQ表情预览
// nt_qq\global\nt_data\Emoji\emoji-resource\face_config.json 里面有所有表情的id, 自带表情id是QSid, 标准emoji表情id是QCid
// 其实以官方文档为准是最好的https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType
emojiId = emojiId.toString()
const session = getSession()
const emojiType = emojiId.length > 3 ? '2' : '1'
if (session) {
return session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiId.length > 3 ? '2' : '1', set)
return session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiType, setEmoji)
} else {
return await invoke({
methodName: NTMethod.EMOJI_LIKE,
args: [
{
peer,
msgSeq,
emojiId,
emojiType: emojiId.length > 3 ? '2' : '1',
setEmoji: set,
},
null,
],
})
return await invoke(NTMethod.EMOJI_LIKE, [{ peer, msgSeq, emojiId, emojiType, setEmoji }, null])
}
}
@@ -75,33 +56,16 @@ export class NTQQMsgApi extends Service {
if (session) {
return session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId)
} else {
return await invoke<GeneralCallResult & { msgList: RawMessage[] }>({
methodName: NTMethod.GET_MULTI_MSG,
args: [
{
peer,
rootMsgId,
parentMsgId,
},
null,
],
})
return await invoke(NTMethod.GET_MULTI_MSG, [{ peer, rootMsgId, parentMsgId }, null])
}
}
async activateChat(peer: Peer) {
return await invoke<GeneralCallResult>({
methodName: NTMethod.ACTIVE_CHAT_PREVIEW,
args: [{ peer, cnt: 20 }, null],
})
return await invoke<GeneralCallResult>(NTMethod.ACTIVE_CHAT_PREVIEW, [{ peer, cnt: 20 }, null])
}
async activateChatAndGetHistory(peer: Peer) {
return await invoke<GeneralCallResult>({
methodName: NTMethod.ACTIVE_CHAT_HISTORY,
// 参数似乎不是这样
args: [{ peer, cnt: 20 }, null],
})
return await invoke<GeneralCallResult>(NTMethod.ACTIVE_CHAT_HISTORY, [{ peer, cnt: 20 }, null])
}
async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) {
@@ -111,60 +75,26 @@ export class NTQQMsgApi extends Service {
if (session) {
return session.getMsgService().getMsgsByMsgId(peer, msgIds)
} else {
return await invoke<GeneralCallResult & {
msgList: RawMessage[]
}>({
methodName: 'nodeIKernelMsgService/getMsgsByMsgId',
args: [
{
peer,
msgIds,
},
null,
],
})
return await invoke('nodeIKernelMsgService/getMsgsByMsgId', [{ peer, msgIds }, null])
}
}
async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) {
async getMsgHistory(peer: Peer, msgId: string, cnt: number, isReverseOrder: boolean = false) {
const session = getSession()
// 消息时间从旧到新
if (session) {
return session.getMsgService().getMsgsIncludeSelf(peer, msgId, count, isReverseOrder)
return session.getMsgService().getMsgsIncludeSelf(peer, msgId, cnt, isReverseOrder)
} else {
return await invoke<GeneralCallResult & { msgList: RawMessage[] }>({
methodName: NTMethod.HISTORY_MSG,
args: [
{
peer,
msgId,
cnt: count,
queryOrder: isReverseOrder,
},
null,
],
})
return await invoke(NTMethod.HISTORY_MSG, [{ peer, msgId, cnt, queryOrder: isReverseOrder }, null])
}
}
async recallMsg(peer: Peer, msgIds: string[]) {
const session = getSession()
if (session) {
return session.getMsgService().recallMsg({
chatType: peer.chatType,
peerUid: peer.peerUid
}, msgIds)
return session.getMsgService().recallMsg(peer, msgIds)
} else {
return await invoke({
methodName: NTMethod.RECALL_MSG,
args: [
{
peer,
msgIds,
},
null,
],
})
return await invoke(NTMethod.RECALL_MSG, [{ peer, msgIds }, null])
}
}
@@ -196,19 +126,9 @@ export class NTQQMsgApi extends Service {
)
msgList = data[1]
} else {
const data = await invoke<{ msgList: RawMessage[] }>({
methodName: 'nodeIKernelMsgService/sendMsg',
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false,
cmdCB: payload => {
for (const msgRecord of payload.msgList) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === 2) {
return true
}
}
return false
},
args: [
const data = await invoke<{ msgList: RawMessage[] }>(
'nodeIKernelMsgService/sendMsg',
[
{
msgId: '0',
peer,
@@ -217,8 +137,20 @@ export class NTQQMsgApi extends Service {
},
null
],
timeout
})
{
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false,
cmdCB: payload => {
for (const msgRecord of payload.msgList) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === 2) {
return true
}
}
return false
},
timeout
}
)
msgList = data.msgList
}
const retMsg = msgList.find(msgRecord => {
@@ -234,19 +166,13 @@ export class NTQQMsgApi extends Service {
if (session) {
return session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], [])
} else {
return await invoke<GeneralCallResult>({
methodName: NTMethod.FORWARD_MSG,
args: [
{
msgIds: msgIds,
srcContact: srcPeer,
dstContacts: [destPeer],
commentElements: [],
msgAttributeInfos: new Map(),
},
null,
],
})
return await invoke<GeneralCallResult>(NTMethod.FORWARD_MSG, [{
msgIds,
srcContact: srcPeer,
dstContacts: [destPeer],
commentElements: [],
msgAttributeInfos: new Map(),
}, null])
}
}
@@ -282,19 +208,9 @@ export class NTQQMsgApi extends Service {
)
msgList = data[1]
} else {
const data = await invoke<{ msgList: RawMessage[] }>({
methodName: 'nodeIKernelMsgService/multiForwardMsgWithComment',
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false,
cmdCB: payload => {
for (const msgRecord of payload.msgList) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == selfUid) {
return true
}
}
return false
},
args: [
const data = await invoke<{ msgList: RawMessage[] }>(
'nodeIKernelMsgService/multiForwardMsgWithComment',
[
{
msgInfos,
srcContact: srcPeer,
@@ -304,7 +220,19 @@ export class NTQQMsgApi extends Service {
},
null,
],
})
{
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false,
cmdCB: payload => {
for (const msgRecord of payload.msgList) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == selfUid) {
return true
}
}
return false
},
}
)
msgList = data.msgList
}
for (const msg of msgList) {
@@ -323,25 +251,17 @@ export class NTQQMsgApi extends Service {
throw new Error('转发消息超时')
}
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
async getMsgsBySeqAndCount(peer: Peer, msgSeq: string, count: number, desc: boolean, z: boolean) {
const session = getSession()
if (session) {
return await session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z)
return await session.getMsgService().getMsgsBySeqAndCount(peer, msgSeq, count, desc, z)
} else {
return await invoke<GeneralCallResult & {
msgList: RawMessage[]
}>({
methodName: 'nodeIKernelMsgService/getMsgsBySeqAndCount',
args: [
{
peer,
cnt: count,
msgSeq: seq,
queryOrder: desc
},
null,
],
})
return await invoke('nodeIKernelMsgService/getMsgsBySeqAndCount', [{
peer,
cnt: count,
msgSeq,
queryOrder: desc
}, null])
}
}
@@ -361,23 +281,12 @@ export class NTQQMsgApi extends Service {
return ret
}
async getSingleMsg(peer: Peer, seq: string) {
async getSingleMsg(peer: Peer, msgSeq: string) {
const session = getSession()
if (session) {
return await session.getMsgService().getSingleMsg(peer, seq)
return await session.getMsgService().getSingleMsg(peer, msgSeq)
} else {
return await invoke<GeneralCallResult & {
msgList: RawMessage[]
}>({
methodName: 'nodeIKernelMsgService/getSingleMsg',
args: [
{
peer,
msgSeq: seq,
},
null,
],
})
return await invoke('nodeIKernelMsgService/getSingleMsg', [{ peer, msgSeq }, null])
}
}
}

View File

@@ -1,5 +1,4 @@
import { invoke, NTMethod } from '../ntcall'
import { GeneralCallResult } from '../services'
import { User, UserDetailInfoByUin, UserDetailInfoByUinV2, UserDetailInfoListenerArg } from '../types'
import { getBuildVersion } from '@/common/utils'
import { getSession } from '@/ntqqapi/wrapper'
@@ -18,21 +17,23 @@ declare module 'cordis' {
}
export class NTQQUserApi extends Service {
static inject = ['ntFriendApi']
constructor(protected ctx: Context) {
super(ctx, 'ntUserApi', true)
}
async setQQAvatar(filePath: string) {
return await invoke<GeneralCallResult>({
methodName: NTMethod.SET_QQ_AVATAR,
args: [
{
path: filePath,
},
async setQQAvatar(path: string) {
return await invoke(
NTMethod.SET_QQ_AVATAR,
[
{ path },
null,
],
timeout: 10 * Time.second, // 10秒不一定够
})
{
timeout: 10 * Time.second, // 10秒不一定够
}
)
}
async fetchUserDetailInfo(uid: string) {
@@ -55,12 +56,9 @@ export class NTQQUserApi extends Service {
)
info = profile
} else {
const result = await invoke<{ info: UserDetailInfoListenerArg }>({
methodName: 'nodeIKernelProfileService/fetchUserDetailInfo',
cbCmd: 'nodeIKernelProfileListener/onUserDetailInfoChanged',
afterFirstCmd: false,
cmdCB: payload => payload.info.uid === uid,
args: [
const result = await invoke<{ info: UserDetailInfoListenerArg }>(
'nodeIKernelProfileService/fetchUserDetailInfo',
[
{
callFrom: 'BuddyProfileStore',
uid: [uid],
@@ -69,7 +67,12 @@ export class NTQQUserApi extends Service {
},
null
],
})
{
cbCmd: 'nodeIKernelProfileListener/onUserDetailInfoChanged',
afterFirstCmd: false,
cmdCB: payload => payload.info.uid === uid,
}
)
info = result.info
}
const ret: User = {
@@ -104,19 +107,21 @@ export class NTQQUserApi extends Service {
)
return profile
} else {
const result = await invoke<{ info: User }>({
methodName: 'nodeIKernelProfileService/getUserDetailInfoWithBizInfo',
cbCmd: 'nodeIKernelProfileListener/onProfileDetailInfoChanged',
afterFirstCmd: false,
cmdCB: (payload) => payload.info.uid === uid,
args: [
const result = await invoke<{ info: User }>(
'nodeIKernelProfileService/getUserDetailInfoWithBizInfo',
[
{
uid,
bizList: [0]
},
null,
],
})
{
cbCmd: 'nodeIKernelProfileListener/onProfileDetailInfoChanged',
afterFirstCmd: false,
cmdCB: (payload) => payload.info.uid === uid,
}
)
return result.info
}
}
@@ -139,7 +144,7 @@ export class NTQQUserApi extends Service {
}
const uin = selfInfo.uin
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + uin + '&clientkey=' + clientKeyData.clientKey + '&u1=https%3A%2F%2F' + domain + '%2F' + uin + '%2Finfocenter&keyindex=19%27'
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl)
const cookies: { [key: string]: string } = await RequestUtil.HttpsGetCookies(requestUrl)
return cookies
}
@@ -165,9 +170,9 @@ export class NTQQUserApi extends Service {
doLikeTollCount: 0
})
} else {
return await invoke<GeneralCallResult & { succCounts: number }>({
methodName: 'nodeIKernelProfileLikeService/setBuddyProfileLike',
args: [
return await invoke(
'nodeIKernelProfileLikeService/setBuddyProfileLike',
[
{
doLikeUserInfo: {
friendUid: uid,
@@ -178,7 +183,7 @@ export class NTQQUserApi extends Service {
},
null,
],
})
)
}
}
@@ -187,7 +192,7 @@ export class NTQQUserApi extends Service {
// 通用转换开始尝试
let uid = (await session?.getUixConvertService().getUid([Uin]))?.uidInfo.get(Uin)
if (!uid) {
let unveifyUid = (await this.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
let unveifyUid = (await this.getUserDetailInfoByUin(Uin)).info.uid //从QQ Native 特殊转换 方法三
if (unveifyUid.indexOf('*') == -1) {
uid = unveifyUid
}
@@ -205,32 +210,11 @@ export class NTQQUserApi extends Service {
uid = (await session.getUixConvertService().getUid([uin])).uidInfo.get(uin)
if (uid) return uid
} else {
let uid = (await invoke<{ uids: Map<string, string> }>({
methodName: 'nodeIKernelGroupService/getUidByUins',
args: [
{ uin: [uin] },
null,
],
})).uids.get(uin)
let uid = (await invoke('nodeIKernelGroupService/getUidByUins', [{ uin: [uin] }])).uids.get(uin)
if (uid) return uid
uid = (await invoke<Map<string, string>>({
methodName: 'nodeIKernelProfileService/getUidByUin',
args: [
{
callFrom: 'FriendsServiceImpl',
uin: [uin],
},
null,
],
})).get(uin)
uid = (await invoke('nodeIKernelProfileService/getUidByUin', [{ callFrom: 'FriendsServiceImpl', uin: [uin] }])).get(uin)
if (uid) return uid
uid = (await invoke<{ uidInfo: Map<string, string> }>({
methodName: 'nodeIKernelUixConvertService/getUid',
args: [
{ uin: [uin] },
null,
],
})).uidInfo.get(uin)
uid = (await invoke('nodeIKernelUixConvertService/getUid', [{ uins: [uin] }])).uidInfo.get(uin)
if (uid) return uid
}
const unveifyUid = (await this.getUserDetailInfoByUinV2(uin)).detail.uid //从QQ Native 特殊转换
@@ -253,13 +237,13 @@ export class NTQQUserApi extends Service {
uin
)
} else {
return await invoke<UserDetailInfoByUinV2>({
methodName: 'nodeIKernelProfileService/getUserDetailInfoByUin',
args: [
return await invoke<UserDetailInfoByUinV2>(
'nodeIKernelProfileService/getUserDetailInfoByUin',
[
{ uin },
null,
],
})
)
}
}
@@ -295,39 +279,18 @@ export class NTQQUserApi extends Service {
if (uin) return uin
uin = (await session.getUixConvertService().getUin([uid])).uinInfo.get(uid)
if (uin) return uin
return uin
} else {
let uin = (await invoke<{ uins: Map<string, string> }>({
methodName: 'nodeIKernelGroupService/getUinByUids',
args: [
{ uid: [uid] },
null,
],
})).uins.get(uid)
let uin = (await invoke('nodeIKernelGroupService/getUinByUids', [{ uid: [uid] }])).uins.get(uid)
if (uin) return uin
uin = (await invoke<Map<string, string>>({
methodName: 'nodeIKernelProfileService/getUinByUid',
args: [
{
callFrom: 'FriendsServiceImpl',
uid: [uid],
},
null,
],
})).get(uid)
uin = (await invoke('nodeIKernelProfileService/getUinByUid', [{ callFrom: 'FriendsServiceImpl', uid: [uid] }])).get(uid)
if (uin) return uin
uin = (await invoke<{ uinInfo: Map<string, string> }>({
methodName: 'nodeIKernelUixConvertService/getUin',
args: [
{ uid: [uid] },
null,
],
})).uinInfo.get(uid)
uin = (await invoke('nodeIKernelUixConvertService/getUin', [{ uids: [uid] }])).uinInfo.get(uid)
if (uin) return uin
}
let uin = (await this.ctx.ntFriendApi.getBuddyIdMap(true)).getKey(uid)
let uin = (await this.ctx.ntFriendApi.getBuddyIdMap(true)).get(uid)
if (uin) return uin
uin = (await this.getUserDetailInfo(uid)).uin //从QQ Native 转换
return uin
}
async getUinByUid(Uid: string) {
@@ -342,12 +305,7 @@ export class NTQQUserApi extends Service {
if (session) {
return await session.getTicketService().forceFetchClientKey('')
} else {
return await invoke<forceFetchClientKeyRetType>({
methodName: 'nodeIKernelTicketService/forceFetchClientKey',
args: [{
domain: ''
}, null],
})
return await invoke('nodeIKernelTicketService/forceFetchClientKey', [{ domain: '' }, null])
}
}

View File

@@ -125,6 +125,8 @@ export interface GroupEssenceMsgRet {
}
export class NTQQWebApi extends Service {
static inject = ['ntUserApi']
constructor(protected ctx: Context) {
super(ctx, 'ntWebApi', true)
}

View File

@@ -42,13 +42,15 @@ export class NTQQWindowApi extends Service {
cbCmd: ReceiveCmd | undefined,
autoCloseSeconds: number = 2,
) {
const result = await invoke<R>({
className: NTClass.WINDOW_API,
methodName: NTMethod.OPEN_EXTRA_WINDOW,
cbCmd,
afterFirstCmd: false,
args: [ntQQWindow.windowName, ...args],
})
const result = await invoke<R>(
NTMethod.OPEN_EXTRA_WINDOW,
[ntQQWindow.windowName, ...args],
{
className: NTClass.WINDOW_API,
cbCmd,
afterFirstCmd: false,
}
)
setTimeout(() => {
for (const w of BrowserWindow.getAllWindows()) {
// log("close window", w.webContents.getURL())

View File

@@ -33,7 +33,6 @@ declare module 'cordis' {
'nt/group-notify': (input: GroupNotify[]) => void
'nt/friend-request': (input: FriendRequest[]) => void
'nt/group-member-info-updated': (input: { groupCode: string; members: GroupMember[] }) => void
'nt/friend-list-updated': (input: { groupCode: string; members: GroupMember[] }) => void
}
}

View File

@@ -1,3 +1,5 @@
import ffmpeg from 'fluent-ffmpeg'
import faceConfig from './helper/face_config.json'
import {
AtType,
ElementType,
@@ -13,22 +15,16 @@ import {
SendTextElement,
SendVideoElement,
} from './types'
import { promises as fs } from 'node:fs'
import ffmpeg from 'fluent-ffmpeg'
import { stat, writeFile, copyFile, unlink } from 'node:fs/promises'
import { calculateFileMD5, isGIF } from '../common/utils/file'
import { defaultVideoThumb, getVideoInfo } from '../common/utils/video'
import { encodeSilk } from '../common/utils/audio'
import faceConfig from './helper/face_config.json'
import { Context } from 'cordis'
import { isNullable } from 'cosmokit'
export const mFaceCache = new Map<string, string>() // emojiId -> faceName
export namespace SendMsgElementConstructor {
export function poke(groupCode: string, uin: string) {
return null
}
export namespace SendElementEntities {
export function text(content: string): SendTextElement {
return {
elementType: ElementType.TEXT,
@@ -123,7 +119,7 @@ export namespace SendMsgElementConstructor {
export async function video(ctx: Context, filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise<SendVideoElement> {
try {
await fs.stat(filePath)
await stat(filePath)
} catch (e) {
throw `文件${filePath}异常,不存在`
}
@@ -165,7 +161,7 @@ export namespace SendMsgElementConstructor {
function useDefaultThumb() {
if (completed) return
ctx.logger.info('获取视频封面失败,使用默认封面')
fs.writeFile(thumbPath, defaultVideoThumb)
writeFile(thumbPath, defaultVideoThumb)
.then(() => {
resolve(thumbPath)
})
@@ -176,7 +172,7 @@ export namespace SendMsgElementConstructor {
ffmpeg(filePath)
.on('error', (err) => {
if (diyThumbPath) {
fs.copyFile(diyThumbPath, thumbPath)
copyFile(diyThumbPath, thumbPath)
.then(() => {
completed = true
resolve(thumbPath)
@@ -201,7 +197,7 @@ export namespace SendMsgElementConstructor {
let thumbPath = new Map()
const _thumbPath = await createThumb
ctx.logger.info('生成视频缩略图', _thumbPath)
const thumbSize = (await fs.stat(_thumbPath)).size
const thumbSize = (await stat(_thumbPath)).size
// log("生成缩略图", _thumbPath)
thumbPath.set(0, _thumbPath)
const thumbMd5 = await calculateFileMD5(_thumbPath)
@@ -246,7 +242,7 @@ export namespace SendMsgElementConstructor {
throw '文件异常大小为0'
}
if (converted) {
fs.unlink(silkPath).then()
unlink(silkPath)
}
return {
elementType: ElementType.PTT,

View File

@@ -56,7 +56,7 @@ const callHooks: Array<{
hookFunc: (callParams: unknown[]) => void | Promise<void>
}> = []
export function hookNTQQApiReceive(window: BrowserWindow) {
export function hookNTQQApiReceive(window: BrowserWindow, onlyLog: boolean) {
const originalSend = window.webContents.send
const patchSend = (channel: string, ...args: NTQQApiReturnData) => {
try {
@@ -65,34 +65,36 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
log(`received ntqq api message: ${channel}`, args)
}
} catch { }
if (args?.[1] instanceof Array) {
for (const receiveData of args?.[1]) {
const ntQQApiMethodName = receiveData.cmdName
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for (const hook of receiveHooks) {
if (hook.method.includes(ntQQApiMethodName)) {
new Promise((resolve, reject) => {
try {
hook.hookFunc(receiveData.payload)
} catch (e: any) {
log('hook error', ntQQApiMethodName, e.stack.toString())
}
resolve(undefined)
}).then()
if (!onlyLog) {
if (args?.[1] instanceof Array) {
for (const receiveData of args?.[1]) {
const ntQQApiMethodName = receiveData.cmdName
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for (const hook of receiveHooks) {
if (hook.method.includes(ntQQApiMethodName)) {
new Promise((resolve, reject) => {
try {
hook.hookFunc(receiveData.payload)
} catch (e: any) {
log('hook error', ntQQApiMethodName, e.stack.toString())
}
resolve(undefined)
}).then()
}
}
}
}
}
if (args[0]?.callbackId) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args[0].callbackId
if (hookApiCallbacks[callbackId]) {
// log("callback found")
new Promise((resolve, reject) => {
hookApiCallbacks[callbackId](args[1])
resolve(undefined)
}).then()
delete hookApiCallbacks[callbackId]
if (args[0]?.callbackId) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args[0].callbackId
if (hookApiCallbacks[callbackId]) {
// log("callback found")
new Promise((resolve, reject) => {
hookApiCallbacks[callbackId](args[1])
resolve(undefined)
}).then()
delete hookApiCallbacks[callbackId]
}
}
}
originalSend.call(window.webContents, channel, ...args)
@@ -100,7 +102,7 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
window.webContents.send = patchSend
}
export function hookNTQQApiCall(window: BrowserWindow) {
export function hookNTQQApiCall(window: BrowserWindow, onlyLog: boolean) {
// 监听调用NTQQApi
let webContents = window.webContents as any
const ipc_message_proxy = webContents._events['-ipc-message']?.[0] || webContents._events['-ipc-message']
@@ -116,23 +118,25 @@ export function hookNTQQApiCall(window: BrowserWindow) {
try {
logHook && log('call NTQQ api', thisArg, args)
} catch (e) { }
try {
const _args: unknown[] = args[3][1]
const cmdName: NTMethod = _args[0] as NTMethod
const callParams = _args.slice(1)
callHooks.forEach((hook) => {
if (hook.method.includes(cmdName)) {
new Promise((resolve, reject) => {
try {
hook.hookFunc(callParams)
} catch (e: any) {
log('hook call error', e, _args)
}
resolve(undefined)
}).then()
}
})
} catch (e) { }
if (!onlyLog) {
try {
const _args: unknown[] = args[3][1]
const cmdName: NTMethod = _args[0] as NTMethod
const callParams = _args.slice(1)
callHooks.forEach((hook) => {
if (hook.method.includes(cmdName)) {
new Promise((resolve, reject) => {
try {
hook.hookFunc(callParams)
} catch (e: any) {
log('hook call error', e, _args)
}
resolve(undefined)
}).then()
}
})
} catch (e) { }
}
}
return target.apply(thisArg, args)
},

View File

@@ -2,7 +2,20 @@ import { ipcMain } from 'electron'
import { hookApiCallbacks, registerReceiveHook, removeReceiveHook } from './hook'
import { log } from '../common/utils/legacyLog'
import { randomUUID } from 'node:crypto'
import { GeneralCallResult } from './services'
import {
GeneralCallResult,
NodeIKernelBuddyService,
NodeIKernelProfileService,
NodeIKernelGroupService,
NodeIKernelProfileLikeService,
NodeIKernelMsgService,
NodeIKernelMSFService,
NodeIKernelUixConvertService,
NodeIKernelRichMediaService,
NodeIKernelTicketService,
NodeIKernelTipOffService,
NodeIKernelSearchService,
} from './services'
export enum NTClass {
NT_API = 'ns-ntApi',
@@ -89,51 +102,67 @@ export enum NTMethod {
}
export enum NTChannel {
IPC_UP_1 = 'IPC_UP_1',
IPC_UP_2 = 'IPC_UP_2',
IPC_UP_3 = 'IPC_UP_3',
IPC_UP_1 = 'IPC_UP_1',
IPC_UP_4 = 'IPC_UP_4'
}
interface InvokeParams<ReturnType> {
methodName: string
interface NTService {
nodeIKernelBuddyService: NodeIKernelBuddyService
nodeIKernelProfileService: NodeIKernelProfileService
nodeIKernelGroupService: NodeIKernelGroupService
nodeIKernelProfileLikeService: NodeIKernelProfileLikeService
nodeIKernelMsgService: NodeIKernelMsgService
nodeIKernelMSFService: NodeIKernelMSFService
nodeIKernelUixConvertService: NodeIKernelUixConvertService
nodeIKernelRichMediaService: NodeIKernelRichMediaService
nodeIKernelTicketService: NodeIKernelTicketService
nodeIKernelTipOffService: NodeIKernelTipOffService
nodeIKernelSearchService: NodeIKernelSearchService
}
interface InvokeOptions<ReturnType> {
className?: NTClass
channel?: NTChannel
classNameIsRegister?: boolean
args?: unknown[]
cbCmd?: string | string[]
cmdCB?: (payload: ReturnType) => boolean
afterFirstCmd?: boolean // 是否在methodName调用完之后再去hook cbCmd
timeout?: number
}
export function invoke<ReturnType>(params: InvokeParams<ReturnType>) {
const className = params.className ?? NTClass.NT_API
const channel = params.channel ?? NTChannel.IPC_UP_2
const timeout = params.timeout ?? 5000
const afterFirstCmd = params.afterFirstCmd ?? true
const uuid = randomUUID()
export function invoke<
R extends Awaited<ReturnType<NTService[S][M] extends (...args: any) => any ? NTService[S][M] : any>>,
S extends keyof NTService = any,
M extends keyof NTService[S] & string = any
>(method: `${unknown extends `${S}/${M}` ? `${S}/${M}` : string}`, args: unknown[], options: InvokeOptions<R> = {}) {
const className = options.className ?? NTClass.NT_API
const channel = options.channel ?? NTChannel.IPC_UP_2
const timeout = options.timeout ?? 5000
const afterFirstCmd = options.afterFirstCmd ?? true
let eventName = className + '-' + channel[channel.length - 1]
if (params.classNameIsRegister) {
if (options.classNameIsRegister) {
eventName += '-register'
}
const apiArgs = [params.methodName, ...(params.args ?? [])]
//log('callNTQQApi', channel, eventName, apiArgs, uuid)
return new Promise((resolve: (data: ReturnType) => void, reject) => {
return new Promise<R>((resolve, reject) => {
const apiArgs = [method, ...args]
const callbackId = randomUUID()
let success = false
if (!params.cbCmd) {
if (!options.cbCmd) {
// QQ后端会返回结果并且可以根据uuid识别
hookApiCallbacks[uuid] = (r: ReturnType) => {
hookApiCallbacks[callbackId] = res => {
success = true
resolve(r)
resolve(res)
}
}
else {
// 这里的callback比较特殊QQ后端先返回是否调用成功再返回一条结果数据
const secondCallback = () => {
const hookId = registerReceiveHook<ReturnType>(params.cbCmd!, (payload) => {
const hookId = registerReceiveHook<R>(options.cbCmd!, (payload) => {
// log(methodName, "second callback", cbCmd, payload, cmdCB);
if (!!params.cmdCB) {
if (params.cmdCB(payload)) {
if (!!options.cmdCB) {
if (options.cmdCB(payload)) {
removeReceiveHook(hookId)
success = true
resolve(payload)
@@ -147,21 +176,21 @@ export function invoke<ReturnType>(params: InvokeParams<ReturnType>) {
})
}
!afterFirstCmd && secondCallback()
hookApiCallbacks[uuid] = (result: GeneralCallResult) => {
hookApiCallbacks[callbackId] = (result: GeneralCallResult) => {
if (result?.result === 0 || result === undefined) {
//log(`${params.methodName} callback`, result)
afterFirstCmd && secondCallback()
}
else {
log('ntqq api call failed', result)
reject(`ntqq api call failed, ${result.errMsg}`)
log('ntqq api call failed,', method, result)
reject(`ntqq api call failed, ${method}, ${result.errMsg}`)
}
}
}
setTimeout(() => {
if (!success) {
log(`ntqq api timeout ${channel}, ${eventName}, ${params.methodName}`, apiArgs)
reject(`ntqq api timeout ${channel}, ${eventName}, ${params.methodName}, ${apiArgs}`)
log(`ntqq api timeout ${channel}, ${eventName}, ${method}`, apiArgs)
reject(`ntqq api timeout ${channel}, ${eventName}, ${method}, ${apiArgs}`)
}
}, timeout)
@@ -173,7 +202,7 @@ export function invoke<ReturnType>(params: InvokeParams<ReturnType>) {
},
},
},
{ type: 'request', callbackId: uuid, eventName },
{ type: 'request', callbackId, eventName },
apiArgs,
)
})

View File

@@ -3,7 +3,7 @@ import {
GroupExtParam,
GroupMember,
GroupMemberRole,
GroupNotifyTypes,
GroupNotifyType,
GroupRequestOperateTypes,
} from '@/ntqqapi/types'
import { GeneralCallResult } from './common'
@@ -181,7 +181,7 @@ export interface NodeIKernelGroupService {
operateType: GroupRequestOperateTypes, // 2 拒绝
targetMsg: {
seq: string, // 通知序列号
type: GroupNotifyTypes,
type: GroupNotifyType,
groupCode: string,
postscript: string
}

View File

@@ -110,8 +110,6 @@ export interface NodeIKernelMsgService {
resendMsg(...args: unknown[]): unknown
recallMsg(...args: unknown[]): unknown
reeditRecallMsg(...args: unknown[]): unknown
//调用请检查除开commentElements其余参数不能为null
forwardMsg(msgIds: string[], srcContact: Peer, dstContacts: Peer[], commentElements: MessageElement[]): Promise<GeneralCallResult>

View File

@@ -74,7 +74,7 @@ export interface NodeIKernelProfileService {
setGander(...args: unknown[]): Promise<unknown>
setHeader(arg: string): Promise<unknown>
setHeader(arg: string): Promise<GeneralCallResult>
setRecommendImgFlag(...args: unknown[]): Promise<unknown>

View File

@@ -173,14 +173,10 @@ export interface NodeIKernelRichMediaService {
downloadFile(commonFile: CommonFileInfo, arg2: unknown, arg3: unknown, savePath: string): unknown
createGroupFolder(arg1: unknown, arg2: unknown): unknown
downloadGroupFolder(arg1: unknown, arg2: unknown, arg3: unknown): unknown
renameGroupFolder(arg1: unknown, arg2: unknown, arg3: unknown): unknown
deleteGroupFolder(arg1: unknown, arg2: unknown): unknown
deleteTransferInfo(arg1: unknown, arg2: unknown): unknown
cancelTransferTask(arg1: unknown, arg2: unknown, arg3: unknown): unknown

View File

@@ -1,13 +1,19 @@
export enum GroupNotifyTypes {
INVITE_ME = 1,
INVITED_JOIN = 4, // 有人接受了邀请入群
JOIN_REQUEST_BY_INVITED = 5, // 有人邀请了别人入群
JOIN_REQUEST = 7,
ADMIN_SET = 8,
KICK_MEMBER = 9,
MEMBER_EXIT = 11, // 主动退出
ADMIN_UNSET = 12, // 我被取消管理员
ADMIN_UNSET_OTHER = 13, // 其他人取消管理员
export enum GroupNotifyType {
INVITED_BY_MEMBER = 1,
REFUSE_INVITED,
REFUSED_BY_ADMINI_STRATOR,
AGREED_TOJOIN_DIRECT, // 有人接受了邀请入群
INVITED_NEED_ADMINI_STRATOR_PASS, // 有人邀请了别人入群
AGREED_TO_JOIN_BY_ADMINI_STRATOR,
REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS,
SET_ADMIN,
KICK_MEMBER_NOTIFY_ADMIN,
KICK_MEMBER_NOTIFY_KICKED,
MEMBER_LEAVE_NOTIFY_ADMIN, // 主动退出
CANCEL_ADMIN_NOTIFY_CANCELED, // 我被取消管理员
CANCEL_ADMIN_NOTIFY_ADMIN, // 其他人取消管理员
TRANSFER_GROUP_NOTIFY_OLDOWNER,
TRANSFER_GROUP_NOTIFY_ADMIN
}
export interface GroupNotifies {
@@ -17,17 +23,18 @@ export interface GroupNotifies {
}
export enum GroupNotifyStatus {
IGNORE = 0,
WAIT_HANDLE = 1,
APPROVE = 2,
REJECT = 3,
KINIT, // 初始化
KUNHANDLE, // 未处理
KAGREED, // 同意
KREFUSED, // 拒绝
KIGNORED // 忽略
}
export interface GroupNotify {
time: number // 自己添加的字段,时间戳,毫秒, 用于判断收到短时间内收到重复的notify
seq: string // 唯一标识符转成数字再除以1000应该就是时间戳
type: GroupNotifyTypes
status: GroupNotifyStatus // 0是已忽略1是未处理2是已同意
type: GroupNotifyType
status: GroupNotifyStatus
group: { groupCode: string; groupName: string }
user1: { uid: string; nickName: string } // 被设置管理员的人
user2: { uid: string; nickName: string } // 操作者

View File

@@ -0,0 +1,17 @@
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
interface Payload {
group_id: number | string
name: string
parent_id?: '/'
}
export class GoCQHTTPCreateGroupFileFolder extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_CreateGroupFileFolder
async _handle(payload: Payload) {
await this.ctx.ntGroupApi.createGroupFileFolder(payload.group_id.toString(), payload.name)
return null
}
}

View File

@@ -2,15 +2,16 @@ import BaseAction from '../BaseAction'
import { ActionName } from '../types'
interface Payload {
group_id: string | number
file_id: string
busid?: 102
group_id: string | number
file_id: string
busid?: 102
}
export class GoCQHTTPDelGroupFile extends BaseAction<Payload, void> {
actionName = ActionName.GoCQHTTP_DelGroupFile
export class GoCQHTTPDelGroupFile extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_DelGroupFile
async _handle(payload: Payload) {
await this.ctx.ntGroupApi.delGroupFile(payload.group_id.toString(), [payload.file_id])
}
async _handle(payload: Payload) {
await this.ctx.ntGroupApi.deleteGroupFile(payload.group_id.toString(), [payload.file_id])
return null
}
}

View File

@@ -0,0 +1,16 @@
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
interface Payload {
group_id: number | string
folder_id: string
}
export class GoCQHTTPDelGroupFolder extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_DelGroupFolder
async _handle(payload: Payload) {
await this.ctx.ntGroupApi.deleteGroupFileFolder(payload.group_id.toString(), payload.folder_id)
return null
}
}

View File

@@ -1,6 +1,6 @@
import BaseAction from '../BaseAction'
import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import { ActionName } from '../types'
import { MessageUnique } from '@/common/utils/messageUnique'
@@ -32,7 +32,7 @@ export class GoCQHTTGetForwardMsgAction extends BaseAction<Payload, Response> {
const msgList = data.msgList
const messages = await Promise.all(
msgList.map(async (msg) => {
const resMsg = await OB11Constructor.message(this.ctx, msg)
const resMsg = await OB11Entities.message(this.ctx, msg)
resMsg.message_id = MessageUnique.createMsg({
chatType: msg.chatType,
peerUid: msg.peerUid,

View File

@@ -2,7 +2,7 @@ import BaseAction from '../BaseAction'
import { OB11Message } from '../../types'
import { ActionName } from '../types'
import { ChatType } from '@/ntqqapi/types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import { RawMessage } from '@/ntqqapi/types'
import { MessageUnique } from '@/common/utils/messageUnique'
@@ -40,7 +40,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
msg.msgShortId = MessageUnique.createMsg({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)
})
)
const ob11MsgList = await Promise.all(msgList.map((msg) => OB11Constructor.message(this.ctx, msg)))
const ob11MsgList = await Promise.all(msgList.map((msg) => OB11Entities.message(this.ctx, msg)))
return { messages: ob11MsgList }
}
}

View File

@@ -0,0 +1,59 @@
import BaseAction from '../BaseAction'
import { GroupNotifyStatus } from '@/ntqqapi/types'
import { ActionName } from '../types'
interface Response {
invited_requests: {
request_id: number
invitor_uin: number
invitor_nick: string
group_id: number
group_name: string
checked: boolean
actor: number
}[]
join_requests: {
request_id: number
requester_uin: number
requester_nick: string
message: string
group_id: number
group_name: string
checked: boolean
actor: number
}[]
}
export class GoCQHTTPGetGroupSystemMsg extends BaseAction<void, Response> {
actionName = ActionName.GoCQHTTP_GetGroupSystemMsg
async _handle(payload: void) {
const singleScreenNotifies = await this.ctx.ntGroupApi.getSingleScreenNotifies(10)
const data: Response = { invited_requests: [], join_requests: [] }
for (const notify of singleScreenNotifies) {
if (notify.type == 1) {
data.invited_requests.push({
request_id: +notify.seq,
invitor_uin: Number(await this.ctx.ntUserApi.getUinByUid(notify.user1.uid)),
invitor_nick: notify.user1.nickName,
group_id: +notify.group.groupCode,
group_name: notify.group.groupName,
checked: notify.status !== GroupNotifyStatus.KUNHANDLE,
actor: notify.user2?.uid ? Number(await this.ctx.ntUserApi.getUinByUid(notify.user2.uid)) : 0
})
} else if (notify.type == 7) {
data.join_requests.push({
request_id: +notify.seq,
requester_uin: Number(await this.ctx.ntUserApi.getUinByUid(notify.user1.uid)),
requester_nick: notify.user1.nickName,
message: notify.postscript,
group_id: +notify.group.groupCode,
group_name: notify.group.groupName,
checked: notify.status !== GroupNotifyStatus.KUNHANDLE,
actor: notify.user2?.uid ? Number(await this.ctx.ntUserApi.getUinByUid(notify.user2.uid)) : 0
})
}
}
return data
}
}

View File

@@ -1,6 +1,6 @@
import BaseAction from '../BaseAction'
import { OB11User } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import { ActionName } from '../types'
import { getBuildVersion } from '@/common/utils'
import { OB11UserSex } from '../../types'
@@ -33,7 +33,7 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
return ret
}
const data = { ...extendData, ...(await this.ctx.ntUserApi.getUserDetailInfo(uid)) }
return OB11Constructor.stranger(data)
return OB11Entities.stranger(data)
} else {
const user_id = payload.user_id.toString()
const extendData = await this.ctx.ntUserApi.getUserDetailInfoByUinV2(user_id)
@@ -52,7 +52,7 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
return ret
}
const data = { ...extendData, ...(await this.ctx.ntUserApi.getUserDetailInfo(uid)) }
return OB11Constructor.stranger(data)
return OB11Entities.stranger(data)
}
}
}

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs'
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
import { SendMsgElementConstructor } from '@/ntqqapi/constructor'
import { SendElementEntities } from '@/ntqqapi/entities'
import { ChatType, SendFileElement } from '@/ntqqapi/types'
import { uri2local } from '@/common/utils'
import { Peer } from '@/ntqqapi/types'
@@ -28,7 +28,7 @@ export class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> {
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg)
}
const sendFileEle = await SendMsgElementConstructor.file(this.ctx, downloadResult.path, payload.name, payload.folder_id)
const sendFileEle = await SendElementEntities.file(this.ctx, downloadResult.path, payload.name, payload.folder_id)
await sendMsg(this.ctx, {
chatType: ChatType.group,
peerUid: payload.group_id?.toString()!,
@@ -62,7 +62,7 @@ export class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null> {
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg)
}
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.ctx, downloadResult.path, payload.name)
const sendFileEle: SendFileElement = await SendElementEntities.file(this.ctx, downloadResult.path, payload.name)
await sendMsg(this.ctx, peer, [sendFileEle], [], true)
return null
}

View File

@@ -1,5 +1,5 @@
import { OB11Group } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
@@ -13,7 +13,7 @@ class GetGroupInfo extends BaseAction<Payload, OB11Group> {
protected async _handle(payload: Payload) {
const group = (await this.ctx.ntGroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString())
if (group) {
return OB11Constructor.group(group)
return OB11Entities.group(group)
} else {
throw `${payload.group_id}不存在`
}

View File

@@ -1,5 +1,5 @@
import { OB11Group } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
@@ -12,7 +12,7 @@ class GetGroupList extends BaseAction<Payload, OB11Group[]> {
protected async _handle(payload: Payload) {
const groupList = await this.ctx.ntGroupApi.getGroups(payload?.no_cache === true || payload?.no_cache === 'true')
return OB11Constructor.groups(groupList)
return OB11Entities.groups(groupList)
}
}

View File

@@ -1,6 +1,6 @@
import BaseAction from '../BaseAction'
import { OB11GroupMember } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import { ActionName } from '../types'
import { selfInfo } from '@/common/globalVars'
import { isNullable } from 'cosmokit'
@@ -22,7 +22,7 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
//log('群成员详细信息结果', info)
Object.assign(member, info)
}
const ret = OB11Constructor.groupMember(payload.group_id.toString(), member)
const ret = OB11Entities.groupMember(payload.group_id.toString(), member)
const self = await this.ctx.ntGroupApi.getGroupMember(payload.group_id.toString(), selfInfo.uid)
if (self?.role === 3 || self?.role === 4) {
const webGroupMembers = await this.ctx.ntWebApi.getGroupMembers(payload.group_id.toString())

View File

@@ -1,5 +1,5 @@
import { OB11GroupMember } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import BaseAction from '../BaseAction'
import { ActionName } from '../types'
import { selfInfo } from '@/common/globalVars'
@@ -17,7 +17,7 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
const groupMembersArr = Array.from(groupMembers.values())
let _groupMembers = groupMembersArr.map(item => {
return OB11Constructor.groupMember(payload.group_id.toString(), item)
return OB11Entities.groupMember(payload.group_id.toString(), item)
})
const MemberMap: Map<number, OB11GroupMember> = new Map<number, OB11GroupMember>()

View File

@@ -1,3 +1,4 @@
import type Adapter from '../adapter'
import GetMsg from './msg/GetMsg'
import GetLoginInfo from './system/GetLoginInfo'
import { GetFriendList, GetFriendWithCategory } from './user/GetFriendList'
@@ -54,7 +55,9 @@ import GoCQHTTPSetEssenceMsg from './go-cqhttp/SetEssenceMsg'
import GoCQHTTPDelEssenceMsg from './go-cqhttp/DelEssenceMsg'
import GetEvent from './llonebot/GetEvent'
import { GoCQHTTPDelGroupFile } from './go-cqhttp/DelGroupFile'
import type Adapter from '../adapter'
import { GoCQHTTPGetGroupSystemMsg } from './go-cqhttp/GetGroupSystemMsg'
import { GoCQHTTPCreateGroupFileFolder } from './go-cqhttp/CreateGroupFileFolder'
import { GoCQHTTPDelGroupFolder } from './go-cqhttp/DelGroupFolder'
export function initActionMap(adapter: Adapter) {
const actionHandlers = [
@@ -116,7 +119,10 @@ export function initActionMap(adapter: Adapter) {
new GoCQHTTHandleQuickOperation(adapter),
new GoCQHTTPSetEssenceMsg(adapter),
new GoCQHTTPDelEssenceMsg(adapter),
new GoCQHTTPDelGroupFile(adapter)
new GoCQHTTPDelGroupFile(adapter),
new GoCQHTTPGetGroupSystemMsg(adapter),
new GoCQHTTPCreateGroupFileFolder(adapter),
new GoCQHTTPDelGroupFolder(adapter)
]
const actionMap = new Map<string, BaseAction<any, any>>()
for (const action of actionHandlers) {

View File

@@ -1,5 +1,5 @@
import { GroupNotify, GroupNotifyStatus } from '@/ntqqapi/types'
import BaseAction from '../BaseAction'
import { GroupNotify, GroupNotifyStatus } from '@/ntqqapi/types'
import { ActionName } from '../types'
interface OB11GroupRequestNotify {
@@ -13,7 +13,7 @@ export default class GetGroupAddRequest extends BaseAction<null, OB11GroupReques
protected async _handle(payload: null): Promise<OB11GroupRequestNotify[]> {
const data = await this.ctx.ntGroupApi.getGroupIgnoreNotifies()
const notifies: GroupNotify[] = data.notifies.filter((notify) => notify.status === GroupNotifyStatus.WAIT_HANDLE)
const notifies: GroupNotify[] = data.notifies.filter((notify) => notify.status === GroupNotifyStatus.KUNHANDLE)
const returnData: OB11GroupRequestNotify[] = []
for (const notify of notifies) {
const uin = await this.ctx.ntUserApi.getUinByUid(notify.user1.uid)

View File

@@ -1,6 +1,6 @@
import BaseAction from '../BaseAction'
import { OB11Message } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import { ActionName } from '../types'
import { MessageUnique } from '@/common/utils/messageUnique'
@@ -28,7 +28,7 @@ class GetMsg extends BaseAction<PayloadType, OB11Message> {
chatType: msgIdWithPeer.Peer.chatType
}
const msg = this.adapter.getMsgCache(msgIdWithPeer.MsgId) ?? (await this.ctx.ntMsgApi.getMsgsByMsgId(peer, [msgIdWithPeer.MsgId])).msgList[0]
const retMsg = await OB11Constructor.message(this.ctx, msg)
const retMsg = await OB11Entities.message(this.ctx, msg)
retMsg.message_id = MessageUnique.createMsg(peer, msg.msgId)!
retMsg.message_seq = retMsg.message_id
retMsg.real_id = retMsg.message_id

View File

@@ -74,4 +74,7 @@ export enum ActionName {
GoCQHTTP_SetEssenceMsg = 'set_essence_msg',
GoCQHTTP_DelEssenceMsg = 'delete_essence_msg',
GoCQHTTP_DelGroupFile = 'delete_group_file',
GoCQHTTP_GetGroupSystemMsg = 'get_group_system_msg',
GoCQHTTP_CreateGroupFileFolder = 'create_group_file_folder',
GoCQHTTP_DelGroupFolder = 'delete_group_folder'
}

View File

@@ -1,6 +1,6 @@
import BaseAction from '../BaseAction'
import { OB11User } from '../../types'
import { OB11Constructor } from '../../constructor'
import { OB11Entities } from '../../entities'
import { ActionName } from '../types'
import { getBuildVersion } from '@/common/utils'
@@ -14,9 +14,9 @@ export class GetFriendList extends BaseAction<Payload, OB11User[]> {
protected async _handle(payload: Payload) {
const refresh = payload?.no_cache === true || payload?.no_cache === 'true'
if (getBuildVersion() >= 26702) {
return OB11Constructor.friendsV2(await this.ctx.ntFriendApi.getBuddyV2(refresh))
return OB11Entities.friendsV2(await this.ctx.ntFriendApi.getBuddyV2(refresh))
}
return OB11Constructor.friends(await this.ctx.ntFriendApi.getFriends(refresh))
return OB11Entities.friends(await this.ctx.ntFriendApi.getFriends(refresh))
}
}
@@ -27,7 +27,7 @@ export class GetFriendWithCategory extends BaseAction<void, any> {
protected async _handle(payload: void) {
if (getBuildVersion() >= 26702) {
//全新逻辑
return OB11Constructor.friendsV2(await this.ctx.ntFriendApi.getBuddyV2ExWithCate(true))
return OB11Entities.friendsV2(await this.ctx.ntFriendApi.getBuddyV2ExWithCate(true))
} else {
throw new Error('this ntqq version not support, must be 26702 or later')
}

View File

@@ -1,14 +1,15 @@
import { Service, Context } from 'cordis'
import { OB11Constructor } from './constructor'
import { OB11Entities } from './entities'
import {
GroupNotify,
GroupNotifyTypes,
GroupNotifyType,
RawMessage,
BuddyReqType,
Peer,
FriendRequest,
GroupMember,
GroupMemberRole
GroupMemberRole,
GroupNotifyStatus
} from '../ntqqapi/types'
import { OB11GroupRequestEvent } from './event/request/OB11GroupRequest'
import { OB11FriendRequestEvent } from './event/request/OB11FriendRequest'
@@ -108,15 +109,14 @@ class OneBot11Adapter extends Service {
private async handleGroupNotify(notifies: GroupNotify[]) {
for (const notify of notifies) {
try {
notify.time = Date.now()
const notifyTime = parseInt(notify.seq) / 1000
const flag = notify.group.groupCode + '|' + notify.seq + '|' + notify.type
if (notifyTime < this.startTime) {
continue
}
if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) {
if ([GroupNotifyType.MEMBER_LEAVE_NOTIFY_ADMIN, GroupNotifyType.KICK_MEMBER_NOTIFY_ADMIN].includes(notify.type)) {
this.ctx.logger.info('有成员退出通知', notify)
const member1Uin = (await this.ctx.ntUserApi.getUinByUid(notify.user1.uid))!
const member1Uin = await this.ctx.ntUserApi.getUinByUid(notify.user1.uid)
let operatorId = member1Uin
let subType: GroupDecreaseSubType = 'leave'
if (notify.user2.uid) {
@@ -127,65 +127,51 @@ class OneBot11Adapter extends Service {
}
subType = 'kick'
}
const groupDecreaseEvent = new OB11GroupDecreaseEvent(
const event = new OB11GroupDecreaseEvent(
parseInt(notify.group.groupCode),
parseInt(member1Uin),
parseInt(operatorId),
subType,
)
this.dispatch(groupDecreaseEvent)
this.dispatch(event)
}
else if ([GroupNotifyTypes.JOIN_REQUEST, GroupNotifyTypes.JOIN_REQUEST_BY_INVITED].includes(notify.type)) {
else if (notify.type === GroupNotifyType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS && notify.status === GroupNotifyStatus.KUNHANDLE) {
this.ctx.logger.info('有加群请求')
let requestQQ = ''
try {
// uid-->uin
requestQQ = (await this.ctx.ntUserApi.getUinByUid(notify.user1.uid))
if (isNaN(parseInt(requestQQ))) {
requestQQ = (await this.ctx.ntUserApi.getUserDetailInfo(notify.user1.uid)).uin
}
} catch (e) {
this.ctx.logger.error('获取加群人QQ号失败 Uid:', notify.user1.uid, e)
}
let invitorId: string
if (notify.type == GroupNotifyTypes.JOIN_REQUEST_BY_INVITED) {
// groupRequestEvent.sub_type = 'invite'
try {
// uid-->uin
invitorId = (await this.ctx.ntUserApi.getUinByUid(notify.user2.uid))
if (isNaN(parseInt(invitorId))) {
invitorId = (await this.ctx.ntUserApi.getUserDetailInfo(notify.user2.uid)).uin
}
} catch (e) {
invitorId = ''
this.ctx.logger.error('获取邀请人QQ号失败 Uid:', notify.user2.uid, e)
}
}
const groupRequestEvent = new OB11GroupRequestEvent(
const requestUin = await this.ctx.ntUserApi.getUinByUid(notify.user1.uid)
const event = new OB11GroupRequestEvent(
parseInt(notify.group.groupCode),
parseInt(requestQQ) || 0,
parseInt(requestUin) || 0,
flag,
notify.postscript,
invitorId! === undefined ? undefined : +invitorId,
'add'
)
this.dispatch(groupRequestEvent)
this.dispatch(event)
}
else if (notify.type == GroupNotifyTypes.INVITE_ME) {
else if (notify.type === GroupNotifyType.INVITED_BY_MEMBER && notify.status === GroupNotifyStatus.KUNHANDLE) {
this.ctx.logger.info('收到邀请我加群通知')
const userId = (await this.ctx.ntUserApi.getUinByUid(notify.user2.uid)) || ''
const groupInviteEvent = new OB11GroupRequestEvent(
const userId = await this.ctx.ntUserApi.getUinByUid(notify.user2.uid)
const event = new OB11GroupRequestEvent(
parseInt(notify.group.groupCode),
parseInt(userId),
parseInt(userId) || 0,
flag,
undefined,
notify.postscript,
undefined,
'invite'
)
this.dispatch(groupInviteEvent)
this.dispatch(event)
}
else if (notify.type === GroupNotifyType.INVITED_NEED_ADMINI_STRATOR_PASS && notify.status === GroupNotifyStatus.KUNHANDLE) {
this.ctx.logger.info('收到群员邀请加群通知')
const userId = await this.ctx.ntUserApi.getUinByUid(notify.user1.uid)
const event = new OB11GroupRequestEvent(
parseInt(notify.group.groupCode),
parseInt(userId) || 0,
flag,
notify.postscript
)
this.dispatch(event)
}
} catch (e: any) {
this.ctx.logger.error('解析群通知失败', e.stack.toString())
this.ctx.logger.error('解析群通知失败', e.stack)
}
}
}
@@ -203,7 +189,7 @@ class OneBot11Adapter extends Service {
message.msgShortId = MessageUnique.createMsg(peer, message.msgId)
this.addMsgCache(message)
OB11Constructor.message(this.ctx, message)
OB11Entities.message(this.ctx, message)
.then((msg) => {
if (!this.config.debug && msg.message.length === 0) {
return
@@ -219,13 +205,13 @@ class OneBot11Adapter extends Service {
})
.catch((e) => this.ctx.logger.error('constructMessage error: ', e.stack.toString()))
OB11Constructor.GroupEvent(this.ctx, message).then((groupEvent) => {
OB11Entities.groupEvent(this.ctx, message).then((groupEvent) => {
if (groupEvent) {
this.dispatch(groupEvent)
}
})
OB11Constructor.PrivateEvent(this.ctx, message).then((privateEvent) => {
OB11Entities.privateEvent(this.ctx, message).then((privateEvent) => {
if (privateEvent) {
this.dispatch(privateEvent)
}
@@ -240,7 +226,7 @@ class OneBot11Adapter extends Service {
if (!oriMessageId) {
continue
}
OB11Constructor.RecallEvent(this.ctx, message, oriMessageId).then((recallEvent) => {
OB11Entities.recallEvent(this.ctx, message, oriMessageId).then((recallEvent) => {
if (recallEvent) {
this.dispatch(recallEvent)
}

View File

@@ -261,7 +261,7 @@ class OB11WebSocketReverse {
this.wsClient.on('close', () => {
disposeHeartBeat()
this.ctx.logger.info('The websocket connection: ' + this.config.url + ' closed, trying reconnecting...')
this.ctx.logger.info(`The websocket connection: ${this.config.url} closed${this.running ? ', trying reconnecting...' : ''}`)
if (this.running) {
this.ctx.setTimeout(() => this.tryConnect(), 3000)
}

View File

@@ -37,7 +37,7 @@ import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent'
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent'
import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent'
import { OB11GroupMsgEmojiLikeEvent } from './event/notice/OB11MsgEmojiLikeEvent'
import { mFaceCache } from '../ntqqapi/constructor'
import { mFaceCache } from '../ntqqapi/entities'
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
@@ -48,7 +48,7 @@ import { omit, isNullable } from 'cosmokit'
import { Context } from 'cordis'
import { selfInfo } from '@/common/globalVars'
export namespace OB11Constructor {
export namespace OB11Entities {
export async function message(ctx: Context, msg: RawMessage): Promise<OB11Message> {
let config = getConfigUtil().getConfig()
const {
@@ -146,34 +146,31 @@ export namespace OB11Constructor {
message_data['data']['text'] = text
}
else if (element.replyElement) {
message_data['type'] = OB11MessageDataType.reply
const { replyElement } = element
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: ''
}
try {
const records = msg.records.find(msgRecord => msgRecord.msgId === element.replyElement.sourceMsgIdInRecords)
const records = msg.records.find(msgRecord => msgRecord.msgId === replyElement.sourceMsgIdInRecords)
if (!records) throw new Error('找不到回复消息')
let replyMsg = (await ctx.ntMsgApi.getMsgsBySeqAndCount({
peerUid: msg.peerUid,
guildId: '',
chatType: msg.chatType,
}, element.replyElement.replayMsgSeq, 1, true, true))?.msgList[0]
let replyMsg = (await ctx.ntMsgApi.getMsgsBySeqAndCount(peer, replyElement.replayMsgSeq, 1, true, true)).msgList[0]
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
const peer = {
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
}
replyMsg = (await ctx.ntMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq))?.msgList[0]
replyMsg = (await ctx.ntMsgApi.getSingleMsg(peer, replyElement.replayMsgSeq)).msgList[0]
}
// 284840486: 合并消息内侧 消息具体定位不到
if ((!replyMsg || records.msgRandom !== replyMsg.msgRandom) && msg.peerUin !== '284840486') {
throw new Error('回复消息消息验证失败')
}
message_data['data']['id'] = replyMsg && MessageUnique.createMsg({
peerUid: msg.peerUid,
guildId: '',
chatType: msg.chatType,
}, replyMsg.msgId)?.toString()
message_data = {
type: OB11MessageDataType.reply,
data: {
id: MessageUnique.createMsg(peer, replyMsg ? replyMsg.msgId : records.msgId).toString()
}
}
} catch (e: any) {
ctx.logger.error('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq)
ctx.logger.error('获取不到引用的消息', replyElement.replayMsgSeq, e.stack)
continue
}
}
@@ -319,7 +316,7 @@ export namespace OB11Constructor {
return resMsg
}
export async function PrivateEvent(ctx: Context, msg: RawMessage): Promise<OB11BaseNoticeEvent | void> {
export async function privateEvent(ctx: Context, msg: RawMessage): Promise<OB11BaseNoticeEvent | void> {
if (msg.chatType !== ChatType.friend) {
return
}
@@ -352,7 +349,7 @@ export namespace OB11Constructor {
}
}
export async function GroupEvent(ctx: Context, msg: RawMessage): Promise<OB11GroupNoticeEvent | void> {
export async function groupEvent(ctx: Context, msg: RawMessage): Promise<OB11GroupNoticeEvent | void> {
if (msg.chatType !== ChatType.group) {
return
}
@@ -427,7 +424,7 @@ export namespace OB11Constructor {
ctx.logger.info(`收到我被踢出或退群提示, 群${msg.peerUid}`, groupElement)
ctx.ntGroupApi.quitGroup(msg.peerUid)
try {
const adminUin = (await ctx.ntGroupApi.getGroupMember(msg.peerUid, groupElement.adminUid))?.uin || (await ctx.ntUserApi.getUidByUin(groupElement.adminUid))
const adminUin = (await ctx.ntGroupApi.getGroupMember(msg.peerUid, groupElement.adminUid))?.uin || (await ctx.ntUserApi.getUinByUid(groupElement.adminUid))
if (adminUin) {
return new OB11GroupDecreaseEvent(
parseInt(msg.peerUid),
@@ -607,7 +604,7 @@ export namespace OB11Constructor {
}
}
export async function RecallEvent(
export async function recallEvent(
ctx: Context,
msg: RawMessage,
shortId: number
@@ -638,13 +635,13 @@ export namespace OB11Constructor {
user_id: parseInt(friend.uin),
nickname: friend.nick,
remark: friend.remark,
sex: OB11Constructor.sex(friend.sex!),
sex: sex(friend.sex!),
level: (friend.qqLevel && calcQQLevel(friend.qqLevel)) || 0,
}
}
export function friends(friends: User[]): OB11User[] {
return friends.map(OB11Constructor.friend)
return friends.map(friend)
}
export function friendsV2(friends: FriendV2[]): OB11User[] {
@@ -689,7 +686,7 @@ export namespace OB11Constructor {
user_id: parseInt(member.uin),
nickname: member.nick,
card: member.cardName,
sex: OB11Constructor.sex(member.sex!),
sex: sex(member.sex!),
age: 0,
area: '',
level: '0',
@@ -701,7 +698,7 @@ export namespace OB11Constructor {
card_changeable: true,
is_robot: member.isRobot,
shut_up_timestamp: member.shutUpTime,
role: OB11Constructor.groupMemberRole(member.role),
role: groupMemberRole(member.role),
title: member.memberSpecialTitle || '',
}
}
@@ -711,7 +708,7 @@ export namespace OB11Constructor {
...user,
user_id: parseInt(user.uin),
nickname: user.nick,
sex: OB11Constructor.sex(user.sex!),
sex: sex(user.sex!),
age: 0,
qid: user.qid,
login_days: 0,
@@ -719,10 +716,6 @@ export namespace OB11Constructor {
}
}
export function groupMembers(group: Group): OB11GroupMember[] {
return group.members.map((m) => OB11Constructor.groupMember(group.groupCode, m))
}
export function group(group: Group): OB11Group {
return {
group_id: parseInt(group.groupCode),
@@ -733,6 +726,6 @@ export namespace OB11Constructor {
}
export function groups(groups: Group[]): OB11Group[] {
return groups.map(OB11Constructor.group)
return groups.map(group)
}
}

View File

@@ -15,7 +15,7 @@ import {
} from '../types'
import { decodeCQCode } from '../cqcode'
import { Peer } from '@/ntqqapi/types/msg'
import { SendMsgElementConstructor } from '@/ntqqapi/constructor'
import { SendElementEntities } from '@/ntqqapi/entities'
import { MessageUnique } from '@/common/utils/messageUnique'
import { selfInfo } from '@/common/globalVars'
import { uri2local } from '@/common/utils'
@@ -37,7 +37,7 @@ export async function createSendElements(
case OB11MessageDataType.text: {
const text = sendMsg.data?.text
if (text) {
sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text))
sendElements.push(SendElementEntities.text(sendMsg.data!.text))
}
}
break
@@ -63,7 +63,7 @@ export async function createSendElements(
}
}
if (isAdmin && remainAtAllCount > 0) {
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, '@全体成员'))
sendElements.push(SendElementEntities.at(atQQ, atQQ, AtType.atAll, '@全体成员'))
}
}
else if (peer.chatType === ChatType.group) {
@@ -71,14 +71,14 @@ export async function createSendElements(
if (atMember) {
const display = `@${atMember.cardName || atMember.nick}`
sendElements.push(
SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, display),
SendElementEntities.at(atQQ, atMember.uid, AtType.atUser, display),
)
} else {
const atNmae = sendMsg.data?.name
const uid = await ctx.ntUserApi.getUidByUin(atQQ) || ''
const display = atNmae ? `@${atNmae}` : ''
sendElements.push(
SendMsgElementConstructor.at(atQQ, uid, AtType.atUser, display),
SendElementEntities.at(atQQ, uid, AtType.atUser, display),
)
}
}
@@ -98,7 +98,7 @@ export async function createSendElements(
)).msgList[0]
if (replyMsg) {
sendElements.push(
SendMsgElementConstructor.reply(
SendElementEntities.reply(
replyMsg.msgSeq,
replyMsg.msgId,
replyMsg.senderUin!,
@@ -112,13 +112,13 @@ export async function createSendElements(
case OB11MessageDataType.face: {
const faceId = sendMsg.data?.id
if (faceId) {
sendElements.push(SendMsgElementConstructor.face(parseInt(faceId)))
sendElements.push(SendElementEntities.face(parseInt(faceId)))
}
}
break
case OB11MessageDataType.mface: {
sendElements.push(
SendMsgElementConstructor.mface(
SendElementEntities.mface(
+sendMsg.data.emoji_package_id,
sendMsg.data.emoji_id,
sendMsg.data.key,
@@ -128,7 +128,7 @@ export async function createSendElements(
}
break
case OB11MessageDataType.image: {
const res = await SendMsgElementConstructor.pic(
const res = await SendElementEntities.pic(
ctx,
(await handleOb11FileLikeMessage(ctx, sendMsg, { deleteAfterSentFiles })).path,
sendMsg.data.summary || '',
@@ -140,7 +140,7 @@ export async function createSendElements(
break
case OB11MessageDataType.file: {
const { path, fileName } = await handleOb11FileLikeMessage(ctx, sendMsg, { deleteAfterSentFiles })
sendElements.push(await SendMsgElementConstructor.file(ctx, path, fileName))
sendElements.push(await SendElementEntities.file(ctx, path, fileName))
}
break
case OB11MessageDataType.video: {
@@ -150,18 +150,18 @@ export async function createSendElements(
const uri2LocalRes = await uri2local(thumb)
if (uri2LocalRes.success) thumb = uri2LocalRes.path
}
const res = await SendMsgElementConstructor.video(ctx, path, fileName, thumb)
const res = await SendElementEntities.video(ctx, path, fileName, thumb)
deleteAfterSentFiles.push(res.videoElement.filePath)
sendElements.push(res)
}
break
case OB11MessageDataType.voice: {
const { path } = await handleOb11FileLikeMessage(ctx, sendMsg, { deleteAfterSentFiles })
sendElements.push(await SendMsgElementConstructor.ptt(ctx, path))
sendElements.push(await SendElementEntities.ptt(ctx, path))
}
break
case OB11MessageDataType.json: {
sendElements.push(SendMsgElementConstructor.ark(sendMsg.data.data))
sendElements.push(SendElementEntities.ark(sendMsg.data.data))
}
break
case OB11MessageDataType.poke: {
@@ -170,12 +170,12 @@ export async function createSendElements(
break
case OB11MessageDataType.dice: {
const resultId = sendMsg.data?.result
sendElements.push(SendMsgElementConstructor.dice(resultId))
sendElements.push(SendElementEntities.dice(resultId))
}
break
case OB11MessageDataType.RPS: {
const resultId = sendMsg.data?.result
sendElements.push(SendMsgElementConstructor.rps(resultId))
sendElements.push(SendElementEntities.rps(resultId))
}
break
}

View File

@@ -1 +1 @@
export const version = '3.31.1'
export const version = '3.31.3'