This commit is contained in:
idranme
2024-10-01 21:09:27 +08:00
parent 496d56f297
commit a7d86f8fe0
15 changed files with 178 additions and 214 deletions

View File

@@ -2,24 +2,7 @@ import fs from 'fs'
import path from 'node:path' import path from 'node:path'
import { getConfigUtil } from '../config' import { getConfigUtil } from '../config'
import { LOG_DIR } from '../globalVars' import { LOG_DIR } from '../globalVars'
import { Dict } from 'cosmokit' import { inspect } from 'node:util'
function truncateString(obj: Dict | null, maxLength = 500) {
if (obj !== null && typeof obj === 'object') {
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === 'string') {
// 如果是字符串且超过指定长度,则截断
if (obj[key].length > maxLength) {
obj[key] = obj[key].substring(0, maxLength) + '...'
}
} else if (typeof obj[key] === 'object') {
// 如果是对象或数组,则递归调用
truncateString(obj[key], maxLength)
}
})
}
return obj
}
export const logFileName = `llonebot-${new Date().toLocaleString('zh-CN')}.log`.replace(/\//g, '-').replace(/:/g, '-') export const logFileName = `llonebot-${new Date().toLocaleString('zh-CN')}.log`.replace(/\//g, '-').replace(/:/g, '-')
@@ -29,9 +12,8 @@ export function log(...msg: unknown[]) {
} }
let logMsg = '' let logMsg = ''
for (const msgItem of msg) { for (const msgItem of msg) {
// 判断是否是对象
if (typeof msgItem === 'object') { if (typeof msgItem === 'object') {
logMsg += JSON.stringify(truncateString(msgItem)) + ' ' logMsg += inspect(msgItem, { depth: 10, compact: true, breakLength: Infinity }) + ' '
continue continue
} }
logMsg += msgItem + ' ' logMsg += msgItem + ' '

View File

@@ -16,7 +16,6 @@ import path from 'node:path'
import { existsSync } from 'node:fs' import { existsSync } from 'node:fs'
import { ReceiveCmdS } from '../hook' import { ReceiveCmdS } from '../hook'
import { RkeyManager } from '@/ntqqapi/helper/rkey' import { RkeyManager } from '@/ntqqapi/helper/rkey'
import { getSession } from '@/ntqqapi/wrapper'
import { OnRichMediaDownloadCompleteParams, Peer } from '@/ntqqapi/types/msg' import { OnRichMediaDownloadCompleteParams, Peer } from '@/ntqqapi/types/msg'
import { calculateFileMD5 } from '@/common/utils/file' import { calculateFileMD5 } from '@/common/utils/file'
import { fileTypeFromFile } from 'file-type' import { fileTypeFromFile } from 'file-type'
@@ -39,39 +38,28 @@ export class NTQQFileApi extends Service {
this.rkeyManager = new RkeyManager(ctx, 'https://llob.linyuchen.net/rkey') this.rkeyManager = new RkeyManager(ctx, 'https://llob.linyuchen.net/rkey')
} }
async getVideoUrl(peer: Peer, msgId: string, elementId: string) { async getVideoUrl(peer: Peer, msgId: string, elementId: string): Promise<string | undefined> {
const session = getSession() const data = await invoke('nodeIKernelRichMediaService/getVideoPlayUrlV2', [{
if (session) { peer,
return (await session.getRichMediaService().getVideoPlayUrlV2( msgId,
peer, elemId: elementId,
msgId, videoCodecFormat: 0,
elementId, params: {
0, downSourceType: 1,
{ downSourceType: 1, triggerType: 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 }])
if (data.result !== 0) {
this.ctx.logger.warn('getVideoUrl', data)
} }
return data.urlResult.domainUrl[0]?.url
} }
async getFileType(filePath: string) { async getFileType(filePath: string) {
return fileTypeFromFile(filePath) return fileTypeFromFile(filePath)
} }
// 上传文件到QQ的文件夹 /** 上传文件到 QQ 的文件夹 */
async uploadFile(filePath: string, elementType = ElementType.Pic, elementSubType = 0) { async uploadFile(filePath: string, elementType = ElementType.Pic, elementSubType = 0) {
const fileMd5 = await calculateFileMD5(filePath) const fileMd5 = await calculateFileMD5(filePath)
let fileName = path.basename(filePath) let fileName = path.basename(filePath)
@@ -174,8 +162,8 @@ export class NTQQFileApi extends Service {
if (url) { if (url) {
const parsedUrl = new URL(IMAGE_HTTP_HOST + url) //临时解析拼接 const parsedUrl = new URL(IMAGE_HTTP_HOST + url) //临时解析拼接
const imageAppid = parsedUrl.searchParams.get('appid') const imageAppid = parsedUrl.searchParams.get('appid')
const isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid) const isNTPic = imageAppid && ['1406', '1407'].includes(imageAppid)
if (isNewPic) { if (isNTPic) {
let rkey = parsedUrl.searchParams.get('rkey') let rkey = parsedUrl.searchParams.get('rkey')
if (rkey) { if (rkey) {
return IMAGE_HTTP_HOST_NT + url return IMAGE_HTTP_HOST_NT + url

View File

@@ -1,8 +1,7 @@
import { Friend, FriendV2, SimpleInfo, CategoryFriend, BuddyListReqType } from '../types' import { Friend, SimpleInfo, CategoryFriend } from '../types'
import { ReceiveCmdS } from '../hook' import { ReceiveCmdS } from '../hook'
import { invoke, NTMethod, NTClass } from '../ntcall' import { invoke, NTMethod, NTClass } from '../ntcall'
import { getSession } from '@/ntqqapi/wrapper' import { getSession } from '@/ntqqapi/wrapper'
import { Dict, pick } from 'cosmokit'
import { Service, Context } from 'cordis' import { Service, Context } from 'cordis'
declare module 'cordis' { declare module 'cordis' {
@@ -60,7 +59,7 @@ export class NTQQFriendApi extends Service {
} }
} }
async getBuddyV2(refresh = false): Promise<FriendV2[]> { async getBuddyV2(refresh = false): Promise<SimpleInfo[]> {
const data = await invoke<{ const data = await invoke<{
buddyCategory: CategoryFriend[] buddyCategory: CategoryFriend[]
userSimpleInfos: Record<string, SimpleInfo> userSimpleInfos: Record<string, SimpleInfo>
@@ -118,12 +117,7 @@ export class NTQQFriendApi extends Service {
} }
async isBuddy(uid: string): Promise<boolean> { async isBuddy(uid: string): Promise<boolean> {
const session = getSession() return await invoke('nodeIKernelBuddyService/isBuddy', [{ uid }])
if (session) {
return session.getBuddyService().isBuddy(uid)
} else {
return await invoke('nodeIKernelBuddyService/isBuddy', [{ uid }, null])
}
} }
async getBuddyRecommendContact(uin: string) { async getBuddyRecommendContact(uin: string) {

View File

@@ -27,17 +27,12 @@ export class NTQQMsgApi extends Service {
} }
} }
async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, setEmoji: boolean = true) { async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, setEmoji: boolean) {
// nt_qq//global//nt_data//Emoji//emoji-resource//sysface_res/apng/ 下可以看到所有QQ表情预览 // 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 // 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 // 其实以官方文档为准是最好的https://bot.q.qq.com/wiki/develop/api-v2/openapi/emoji/model.html#EmojiType
const session = getSession()
const emojiType = emojiId.length > 3 ? '2' : '1' const emojiType = emojiId.length > 3 ? '2' : '1'
if (session) { return await invoke(NTMethod.EMOJI_LIKE, [{ peer, msgSeq, emojiId, emojiType, setEmoji }])
return session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiType, setEmoji)
} else {
return await invoke(NTMethod.EMOJI_LIKE, [{ peer, msgSeq, emojiId, emojiType, setEmoji }, null])
}
} }
async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string) { async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string) {
@@ -58,59 +53,41 @@ export class NTQQMsgApi extends Service {
} }
async getAioFirstViewLatestMsgs(peer: Peer, cnt: number) { async getAioFirstViewLatestMsgs(peer: Peer, cnt: number) {
return await invoke('nodeIKernelMsgService/getAioFirstViewLatestMsgs', [{ peer, cnt }, null]) return await invoke('nodeIKernelMsgService/getAioFirstViewLatestMsgs', [{ peer, cnt }])
} }
async getMsgsByMsgId(peer: Peer, msgIds: string[]) { async getMsgsByMsgId(peer: Peer, msgIds: string[]) {
if (!peer) throw new Error('peer is not allowed') if (!peer) throw new Error('peer is not allowed')
if (!msgIds) throw new Error('msgIds is not allowed') if (!msgIds) throw new Error('msgIds is not allowed')
const session = getSession() return await invoke('nodeIKernelMsgService/getMsgsByMsgId', [{ peer, msgIds }])
if (session) {
return session.getMsgService().getMsgsByMsgId(peer, msgIds)
} else {
return await invoke('nodeIKernelMsgService/getMsgsByMsgId', [{ peer, msgIds }, null])
}
} }
async getMsgHistory(peer: Peer, msgId: string, cnt: number, isReverseOrder: boolean = false) { async getMsgHistory(peer: Peer, msgId: string, cnt: number, isReverseOrder: boolean = false) {
const session = getSession()
// 消息时间从旧到新 // 消息时间从旧到新
if (session) { return await invoke(NTMethod.HISTORY_MSG, [{ peer, msgId, cnt, queryOrder: isReverseOrder }])
return session.getMsgService().getMsgsIncludeSelf(peer, msgId, cnt, isReverseOrder)
} else {
return await invoke(NTMethod.HISTORY_MSG, [{ peer, msgId, cnt, queryOrder: isReverseOrder }, null])
}
} }
async recallMsg(peer: Peer, msgIds: string[]) { async recallMsg(peer: Peer, msgIds: string[]) {
const session = getSession() return await invoke(NTMethod.RECALL_MSG, [{ peer, msgIds }])
if (session) {
return session.getMsgService().recallMsg(peer, msgIds)
} else {
return await invoke(NTMethod.RECALL_MSG, [{ peer, msgIds }, null])
}
} }
async sendMsg(peer: Peer, msgElements: SendMessageElement[], timeout = 10000) { async sendMsg(peer: Peer, msgElements: SendMessageElement[], timeout = 10000) {
const msgId = await this.generateMsgUniqueId(peer.chatType) const uniqueId = await this.generateMsgUniqueId(peer.chatType)
peer.guildId = msgId peer.guildId = uniqueId
const data = await invoke<{ msgList: RawMessage[] }>( const data = await invoke<{ msgList: RawMessage[] }>(
'nodeIKernelMsgService/sendMsg', 'nodeIKernelMsgService/sendMsg',
[ [{
{ msgId: '0',
msgId: '0', peer,
peer, msgElements,
msgElements, msgAttributeInfos: new Map()
msgAttributeInfos: new Map() }],
},
null
],
{ {
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate', cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false, afterFirstCmd: false,
cmdCB: payload => { cmdCB: payload => {
for (const msgRecord of payload.msgList) { for (const msgRecord of payload.msgList) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === 2) { if (msgRecord.guildId === uniqueId && msgRecord.sendStatus === 2) {
return true return true
} }
} }
@@ -119,22 +96,35 @@ export class NTQQMsgApi extends Service {
timeout timeout
} }
) )
return data.msgList.find(msgRecord => msgRecord.guildId === msgId) return data.msgList.find(msgRecord => msgRecord.guildId === uniqueId)
} }
async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) { async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
const session = getSession() const uniqueId = await this.generateMsgUniqueId(destPeer.chatType)
if (session) { destPeer.guildId = uniqueId
return session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], []) const data = await invoke<{ msgList: RawMessage[] }>(
} else { 'nodeIKernelMsgService/forwardMsg',
return await invoke(NTMethod.FORWARD_MSG, [{ [{
msgIds, msgIds,
srcContact: srcPeer, srcContact: srcPeer,
dstContacts: [destPeer], dstContacts: [destPeer],
commentElements: [], commentElements: [],
msgAttributeInfos: new Map(), msgAttributeInfos: new Map(),
}, null]) }],
} {
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false,
cmdCB: payload => {
for (const msgRecord of payload.msgList) {
if (msgRecord.guildId === uniqueId && msgRecord.sendStatus === 2) {
return true
}
}
return false
}
}
)
return data.msgList.filter(msgRecord => msgRecord.guildId === uniqueId)
} }
async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<RawMessage> { async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise<RawMessage> {
@@ -145,27 +135,24 @@ export class NTQQMsgApi extends Service {
const selfUid = selfInfo.uid const selfUid = selfInfo.uid
const data = await invoke<{ msgList: RawMessage[] }>( const data = await invoke<{ msgList: RawMessage[] }>(
'nodeIKernelMsgService/multiForwardMsgWithComment', 'nodeIKernelMsgService/multiForwardMsgWithComment',
[ [{
{ msgInfos,
msgInfos, srcContact: srcPeer,
srcContact: srcPeer, dstContact: destPeer,
dstContact: destPeer, commentElements: [],
commentElements: [], msgAttributeInfos: new Map(),
msgAttributeInfos: new Map(), }],
},
null,
],
{ {
cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate', cbCmd: 'nodeIKernelMsgListener/onMsgInfoListUpdate',
afterFirstCmd: false, afterFirstCmd: false,
cmdCB: payload => { cmdCB: payload => {
for (const msgRecord of payload.msgList) { for (const msgRecord of payload.msgList) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == selfUid) { if (msgRecord.peerUid === destPeer.peerUid && msgRecord.senderUid === selfUid) {
return true return true
} }
} }
return false return false
}, }
} }
) )
for (const msg of data.msgList) { for (const msg of data.msgList) {
@@ -174,10 +161,10 @@ export class NTQQMsgApi extends Service {
continue continue
} }
const forwardData = JSON.parse(arkElement.arkElement!.bytesData) const forwardData = JSON.parse(arkElement.arkElement!.bytesData)
if (forwardData.app != 'com.tencent.multimsg') { if (forwardData.app !== 'com.tencent.multimsg') {
continue continue
} }
if (msg.peerUid == destPeer.peerUid && msg.senderUid == selfUid) { if (msg.peerUid === destPeer.peerUid && msg.senderUid === selfUid) {
return msg return msg
} }
} }
@@ -240,7 +227,7 @@ export class NTQQMsgApi extends Service {
isIncludeCurrent: true, isIncludeCurrent: true,
pageLimit: 1, pageLimit: 1,
} }
}, null]) }])
} }
async setMsgRead(peer: Peer) { async setMsgRead(peer: Peer) {
@@ -254,7 +241,7 @@ export class NTQQMsgApi extends Service {
emojiId, emojiId,
emojiType, emojiType,
cnt: count cnt: count
}, null]) }])
} }
async fetchFavEmojiList(count: number) { async fetchFavEmojiList(count: number) {
@@ -267,7 +254,8 @@ export class NTQQMsgApi extends Service {
} }
async generateMsgUniqueId(chatType: number) { async generateMsgUniqueId(chatType: number) {
const uniqueId = await invoke('nodeIKernelMsgService/generateMsgUniqueId', [{ chatType }]) const time = await this.getServerTime()
const uniqueId = await invoke('nodeIKernelMsgService/generateMsgUniqueId', [{ chatType, time }])
if (typeof uniqueId === 'string') { if (typeof uniqueId === 'string') {
return uniqueId return uniqueId
} else { } else {
@@ -292,10 +280,15 @@ export class NTQQMsgApi extends Service {
isIncludeCurrent: true, isIncludeCurrent: true,
pageLimit: 1, pageLimit: 1,
} }
}, null]) }])
} }
getMsgTimeFromId(msgId: string) { getMsgTimeFromId(msgId: string) {
// 小概率相差1毫秒
return String(BigInt(msgId) >> 32n) return String(BigInt(msgId) >> 32n)
} }
async getServerTime() {
return await invoke('nodeIKernelMSFService/getServerTime', [null])
}
} }

View File

@@ -1,9 +1,9 @@
import { User, UserDetailInfoByUin, UserDetailInfoByUinV2, UserDetailInfoListenerArg, UserDetailSource, ProfileBizType } from '../types' import { User, UserDetailInfoByUin, UserDetailInfoByUinV2, UserDetailInfo, UserDetailSource, ProfileBizType, SimpleInfo } from '../types'
import { invoke } from '../ntcall' import { invoke } from '../ntcall'
import { getBuildVersion } from '@/common/utils' import { getBuildVersion } from '@/common/utils'
import { getSession } from '@/ntqqapi/wrapper' import { getSession } from '@/ntqqapi/wrapper'
import { RequestUtil } from '@/common/utils/request' import { RequestUtil } from '@/common/utils/request'
import { Time } from 'cosmokit' import { isNullable, Time } from 'cosmokit'
import { Service, Context } from 'cordis' import { Service, Context } from 'cordis'
import { selfInfo } from '@/common/globalVars' import { selfInfo } from '@/common/globalVars'
@@ -34,17 +34,14 @@ export class NTQQUserApi extends Service {
} }
async fetchUserDetailInfo(uid: string) { async fetchUserDetailInfo(uid: string) {
const result = await invoke<{ info: UserDetailInfoListenerArg }>( const result = await invoke<{ info: UserDetailInfo }>(
'nodeIKernelProfileService/fetchUserDetailInfo', 'nodeIKernelProfileService/fetchUserDetailInfo',
[ [{
{ callFrom: 'BuddyProfileStore',
callFrom: 'BuddyProfileStore', uid: [uid],
uid: [uid], source: UserDetailSource.KSERVER,
source: UserDetailSource.KSERVER, bizList: [ProfileBizType.KALL]
bizList: [ProfileBizType.KALL] }],
},
null
],
{ {
cbCmd: 'nodeIKernelProfileListener/onUserDetailInfoChanged', cbCmd: 'nodeIKernelProfileListener/onUserDetailInfoChanged',
afterFirstCmd: false, afterFirstCmd: false,
@@ -70,13 +67,10 @@ export class NTQQUserApi extends Service {
} }
const result = await invoke<{ info: User }>( const result = await invoke<{ info: User }>(
'nodeIKernelProfileService/getUserDetailInfoWithBizInfo', 'nodeIKernelProfileService/getUserDetailInfoWithBizInfo',
[ [{
{ uid,
uid, bizList: [0]
bizList: [0] }],
},
null,
],
{ {
cbCmd: 'nodeIKernelProfileListener/onProfileDetailInfoChanged', cbCmd: 'nodeIKernelProfileListener/onProfileDetailInfoChanged',
afterFirstCmd: false, afterFirstCmd: false,
@@ -129,9 +123,7 @@ export class NTQQUserApi extends Service {
} }
async getUidByUinV1(uin: string) { async getUidByUinV1(uin: string) {
const session = getSession() let uid = (await invoke('nodeIKernelUixConvertService/getUid', [{ uins: [uin] }])).uidInfo.get(uin)
// 通用转换开始尝试
let uid = (await session?.getUixConvertService().getUid([uin]))?.uidInfo.get(uin)
if (!uid) { if (!uid) {
for (const membersList of this.ctx.ntGroupApi.groupMembers.values()) { //从群友列表转 for (const membersList of this.ctx.ntGroupApi.groupMembers.values()) { //从群友列表转
for (const member of membersList.values()) { for (const member of membersList.values()) {
@@ -181,20 +173,14 @@ export class NTQQUserApi extends Service {
async getUserDetailInfoByUinV2(uin: string) { async getUserDetailInfoByUinV2(uin: string) {
return await invoke<UserDetailInfoByUinV2>( return await invoke<UserDetailInfoByUinV2>(
'nodeIKernelProfileService/getUserDetailInfoByUin', 'nodeIKernelProfileService/getUserDetailInfoByUin',
[ [{ uin }]
{ uin },
null,
],
) )
} }
async getUserDetailInfoByUin(uin: string) { async getUserDetailInfoByUin(uin: string) {
return await invoke<UserDetailInfoByUin>( return await invoke<UserDetailInfoByUin>(
'nodeIKernelProfileService/getUserDetailInfoByUin', 'nodeIKernelProfileService/getUserDetailInfoByUin',
[ [{ uin }]
{ uin },
null,
],
) )
} }
@@ -202,31 +188,21 @@ export class NTQQUserApi extends Service {
const ret = await invoke('nodeIKernelUixConvertService/getUin', [{ uids: [uid] }]) const ret = await invoke('nodeIKernelUixConvertService/getUin', [{ uids: [uid] }])
let uin = ret.uinInfo.get(uid) let uin = ret.uinInfo.get(uid)
if (!uin) { if (!uin) {
uin = (await this.getUserDetailInfo(uid)).uin //从QQ Native 转换 uin = (await this.getUserDetailInfo(uid)).uin
} }
return uin return uin
} }
async getUinByUidV2(uid: string) { async getUinByUidV2(uid: string) {
const session = getSession() let uin = (await invoke('nodeIKernelGroupService/getUinByUids', [{ uid: [uid] }])).uins.get(uid)
if (session) {
let uin = (await session.getGroupService().getUinByUids([uid])).uins.get(uid)
if (uin) return uin
uin = (await session.getProfileService().getUinByUid('FriendsServiceImpl', [uid])).get(uid)
if (uin) return uin
uin = (await session.getUixConvertService().getUin([uid])).uinInfo.get(uid)
if (uin) return uin
} else {
let uin = (await invoke('nodeIKernelGroupService/getUinByUids', [{ uid: [uid] }])).uins.get(uid)
if (uin) return uin
uin = (await invoke('nodeIKernelProfileService/getUinByUid', [{ callFrom: 'FriendsServiceImpl', uid: [uid] }])).get(uid)
if (uin) return uin
uin = (await invoke('nodeIKernelUixConvertService/getUin', [{ uids: [uid] }])).uinInfo.get(uid)
if (uin) return uin
}
let uin = (await this.ctx.ntFriendApi.getBuddyIdMap(true)).get(uid)
if (uin) return uin if (uin) return uin
uin = (await this.getUserDetailInfo(uid)).uin //从QQ Native 转换 uin = (await invoke('nodeIKernelProfileService/getUinByUid', [{ callFrom: 'FriendsServiceImpl', uid: [uid] }])).get(uid)
if (uin) return uin
uin = (await invoke('nodeIKernelUixConvertService/getUin', [{ uids: [uid] }])).uinInfo.get(uid)
if (uin) return uin
uin = (await this.ctx.ntFriendApi.getBuddyIdMap(true)).get(uid)
if (uin) return uin
uin = (await this.getUserDetailInfo(uid)).uin
return uin return uin
} }
@@ -246,13 +222,10 @@ export class NTQQUserApi extends Service {
} }
} }
async getSelfNick(refresh = false) { async getSelfNick(refresh = true) {
if ((refresh || !selfInfo.nick) && selfInfo.uid) { if ((refresh || !selfInfo.nick) && selfInfo.uid) {
const userInfo = await this.getUserDetailInfo(selfInfo.uid) const { profiles } = await this.getUserSimpleInfo(selfInfo.uid)
if (userInfo) { selfInfo.nick = profiles[selfInfo.uid].coreInfo.nick
Object.assign(selfInfo, { nick: userInfo.nick })
return userInfo.nick
}
} }
return selfInfo.nick return selfInfo.nick
} }
@@ -281,4 +254,44 @@ export class NTQQUserApi extends Service {
} }
}, null]) }, null])
} }
async getUserSimpleInfo(uid: string, force = true) {
return await invoke<{ profiles: Record<string, SimpleInfo> }>(
'nodeIKernelProfileService/getUserSimpleInfo',
[{
uids: [uid],
force
}],
{
cbCmd: 'onProfileSimpleChanged',
afterFirstCmd: false,
cmdCB: payload => !isNullable(payload.profiles[uid]),
}
)
}
async getCoreAndBaseInfo(uids: string[]) {
return await invoke(
'nodeIKernelProfileService/getCoreAndBaseInfo',
[{
uids,
callFrom: 'nodeStore'
}]
)
}
async getRobotUinRange() {
const data = await invoke(
'nodeIKernelRobotService/getRobotUinRange',
[{
req: {
justFetchMsgConfig: '1',
type: 1,
version: 0,
aioKeywordVersion: 0
}
}]
)
return data.response.robotUinRanges
}
} }

View File

@@ -31,30 +31,18 @@ export class RkeyManager {
isExpired(): boolean { isExpired(): boolean {
const now = new Date().getTime() / 1000 const now = new Date().getTime() / 1000
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`)
return now > this.rkeyData.expired_time return now > this.rkeyData.expired_time
} }
async refreshRkey() { async refreshRkey() {
//刷新rkey
this.rkeyData = await this.fetchServerRkey() this.rkeyData = await this.fetchServerRkey()
} }
async fetchServerRkey() { async fetchServerRkey(): Promise<ServerRkeyData> {
return new Promise<ServerRkeyData>((resolve, reject) => { const response = await fetch(this.serverUrl)
fetch(this.serverUrl) if (!response.ok) {
.then(response => { throw new Error(response.statusText)
if (!response.ok) { }
return reject(response.statusText) // 请求失败,返回错误信息 return response.json()
}
return response.json() // 解析 JSON 格式的响应体
})
.then(data => {
resolve(data)
})
.catch(error => {
reject(error)
})
})
} }
} }

View File

@@ -26,7 +26,6 @@ export enum ReceiveCmdS {
SELF_STATUS = 'nodeIKernelProfileListener/onSelfStatusChanged', SELF_STATUS = 'nodeIKernelProfileListener/onSelfStatusChanged',
CACHE_SCAN_FINISH = 'nodeIKernelStorageCleanListener/onFinishScan', CACHE_SCAN_FINISH = 'nodeIKernelStorageCleanListener/onFinishScan',
MEDIA_UPLOAD_COMPLETE = 'nodeIKernelMsgListener/onRichMediaUploadComplete', MEDIA_UPLOAD_COMPLETE = 'nodeIKernelMsgListener/onRichMediaUploadComplete',
SKEY_UPDATE = 'onSkeyUpdate',
} }
type NTReturnData = [ type NTReturnData = [
@@ -96,7 +95,7 @@ export function hookNTQQApiCall(window: BrowserWindow, onlyLog: boolean) {
const isLogger = args[3]?.[0]?.eventName?.startsWith('ns-LoggerApi') const isLogger = args[3]?.[0]?.eventName?.startsWith('ns-LoggerApi')
if (!isLogger) { if (!isLogger) {
try { try {
logHook && log('call NTQQ api', thisArg, args) logHook && log('call NTQQ api', args)
} catch (e) { } } catch (e) { }
if (!onlyLog) { if (!onlyLog) {
try { try {

View File

@@ -13,7 +13,8 @@ import {
NodeIKernelUixConvertService, NodeIKernelUixConvertService,
NodeIKernelRichMediaService, NodeIKernelRichMediaService,
NodeIKernelTicketService, NodeIKernelTicketService,
NodeIKernelTipOffService NodeIKernelTipOffService,
NodeIKernelRobotService
} from './services' } from './services'
export enum NTClass { export enum NTClass {
@@ -39,7 +40,6 @@ export enum NTMethod {
MEDIA_FILE_PATH = 'nodeIKernelMsgService/getRichMediaFilePathForGuild', MEDIA_FILE_PATH = 'nodeIKernelMsgService/getRichMediaFilePathForGuild',
RECALL_MSG = 'nodeIKernelMsgService/recallMsg', RECALL_MSG = 'nodeIKernelMsgService/recallMsg',
EMOJI_LIKE = 'nodeIKernelMsgService/setMsgEmojiLikes', EMOJI_LIKE = 'nodeIKernelMsgService/setMsgEmojiLikes',
FORWARD_MSG = 'nodeIKernelMsgService/forwardMsgWithComment',
SELF_INFO = 'fetchAuthData', SELF_INFO = 'fetchAuthData',
FILE_TYPE = 'getFileType', FILE_TYPE = 'getFileType',
@@ -93,6 +93,7 @@ interface NTService {
nodeIKernelRichMediaService: NodeIKernelRichMediaService nodeIKernelRichMediaService: NodeIKernelRichMediaService
nodeIKernelTicketService: NodeIKernelTicketService nodeIKernelTicketService: NodeIKernelTicketService
nodeIKernelTipOffService: NodeIKernelTipOffService nodeIKernelTipOffService: NodeIKernelTipOffService
nodeIKernelRobotService: NodeIKernelRobotService
} }
interface InvokeOptions<ReturnType> { interface InvokeOptions<ReturnType> {

View File

@@ -10,7 +10,9 @@ export interface NodeIKernelMsgService {
setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult> setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult>
forwardMsg(msgIds: string[], srcContact: Peer, dstContacts: Peer[], commentElements: MessageElement[]): Promise<GeneralCallResult> forwardMsg(msgIds: string[], srcContact: Peer, dstContacts: Peer[], commentElements: MessageElement[]): Promise<GeneralCallResult & {
detailErr: Map<unknown, unknown>
}>
forwardMsgWithComment(...args: unknown[]): Promise<GeneralCallResult> forwardMsgWithComment(...args: unknown[]): Promise<GeneralCallResult>
@@ -71,7 +73,7 @@ export interface NodeIKernelMsgService {
downloadRichMedia(...args: unknown[]): unknown downloadRichMedia(...args: unknown[]): unknown
setMsgEmojiLikes(...args: unknown[]): unknown setMsgEmojiLikes(...args: unknown[]): Promise<GeneralCallResult>
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<{ getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<{
result: number result: number

View File

@@ -0,0 +1,13 @@
import { GeneralCallResult } from './common'
export interface NodeIKernelRobotService {
getRobotUinRange(req: unknown): Promise<GeneralCallResult & {
response: {
version: number
robotUinRanges: {
minUin: string
maxUin: string
}[]
}
}>
}

View File

@@ -9,3 +9,4 @@ export * from './NodeIKernelUixConvertService'
export * from './NodeIKernelRichMediaService' export * from './NodeIKernelRichMediaService'
export * from './NodeIKernelTicketService' export * from './NodeIKernelTicketService'
export * from './NodeIKernelTipOffService' export * from './NodeIKernelTipOffService'
export * from './NodeIKernelRobotService'

View File

@@ -221,11 +221,6 @@ interface RelationFlags {
isHidePrivilegeIcon: number isHidePrivilegeIcon: number
} }
export interface FriendV2 extends SimpleInfo {
categoryId?: number
categroyName?: string
}
interface CommonExt { interface CommonExt {
constellation: number constellation: number
shengXiao: number shengXiao: number
@@ -255,7 +250,7 @@ interface PhotoWall {
picList: Pic[] picList: Pic[]
} }
export interface UserDetailInfoListenerArg { export interface UserDetailInfo {
uid: string uid: string
uin: string uin: string
simpleInfo: SimpleInfo simpleInfo: SimpleInfo

View File

@@ -19,8 +19,8 @@ abstract class ForwardSingleMsg extends BaseAction<Payload, null> {
} }
const peer = await createPeer(this.ctx, payload) const peer = await createPeer(this.ctx, payload)
const ret = await this.ctx.ntMsgApi.forwardMsg(msg.peer, peer, [msg.msgId]) const ret = await this.ctx.ntMsgApi.forwardMsg(msg.peer, peer, [msg.msgId])
if (ret.result !== 0) { if (ret.length === 0) {
throw new Error(`转发消息失败 ${ret.errMsg}`) throw new Error(`转发消息失败`)
} }
return null return null
} }

View File

@@ -30,9 +30,6 @@ class GetMsg extends BaseAction<PayloadType, OB11Message> {
if (!retMsg) { if (!retMsg) {
throw new Error('消息为空') throw new Error('消息为空')
} }
retMsg.message_id = this.ctx.store.createMsgShortId(peer, msg.msgId)
retMsg.message_seq = retMsg.message_id
retMsg.real_id = retMsg.message_id
return retMsg return retMsg
} }
} }

View File

@@ -8,17 +8,15 @@ export interface MsgEmojiLike {
export class OB11GroupMsgEmojiLikeEvent extends OB11GroupNoticeEvent { export class OB11GroupMsgEmojiLikeEvent extends OB11GroupNoticeEvent {
notice_type = 'group_msg_emoji_like' notice_type = 'group_msg_emoji_like'
message_id: number message_id: number
sub_type?: 'ban' | 'lift_ban'
likes: MsgEmojiLike[] likes: MsgEmojiLike[]
group_id: number group_id: number
user_id: number user_id: number
constructor(groupId: number, userId: number, messageId: number, likes: MsgEmojiLike[], sub_type?: 'ban' | 'lift_ban') { constructor(groupId: number, userId: number, messageId: number, likes: MsgEmojiLike[]) {
super() super()
this.group_id = groupId this.group_id = groupId
this.user_id = userId // 可为空表示是对别人的消息操作如果是对bot自己的消息则不为空 this.user_id = userId // 可为空表示是对别人的消息操作如果是对bot自己的消息则不为空
this.message_id = messageId this.message_id = messageId
this.likes = likes this.likes = likes
this.sub_type = sub_type
} }
} }