mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
commit
a58fb31f8e
@ -4,7 +4,7 @@
|
|||||||
"name": "LLOneBot",
|
"name": "LLOneBot",
|
||||||
"slug": "LLOneBot",
|
"slug": "LLOneBot",
|
||||||
"description": "实现 OneBot 11 协议,用于 QQ 机器人开发",
|
"description": "实现 OneBot 11 协议,用于 QQ 机器人开发",
|
||||||
"version": "3.33.7",
|
"version": "3.33.8",
|
||||||
"icon": "./icon.webp",
|
"icon": "./icon.webp",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@ -236,7 +236,7 @@ export class NTQQFileCacheApi extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scanCache() {
|
scanCache() {
|
||||||
invoke<GeneralCallResult>(ReceiveCmdS.CACHE_SCAN_FINISH, [], { classNameIsRegister: true })
|
invoke<GeneralCallResult>(ReceiveCmdS.CACHE_SCAN_FINISH, [], { registerEvent: true })
|
||||||
return invoke<CacheScanResult>(NTMethod.CACHE_SCAN, [null, null], { timeout: 300 * Time.second })
|
return invoke<CacheScanResult>(NTMethod.CACHE_SCAN, [null, null], { timeout: 300 * Time.second })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,52 +101,20 @@ export class NTQQFriendApi extends Service {
|
|||||||
return retMap
|
return retMap
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBuddyV2ExWithCate(refresh = false) {
|
async getBuddyV2WithCate(refresh = false) {
|
||||||
const session = getSession()
|
const data = await invoke<{
|
||||||
if (session) {
|
buddyCategory: CategoryFriend[]
|
||||||
const uids: string[] = []
|
userSimpleInfos: Record<string, SimpleInfo>
|
||||||
const categoryMap: Map<string, Dict> = new Map()
|
}>(
|
||||||
const buddyService = session.getBuddyService()
|
'getBuddyList',
|
||||||
const buddyListV2 = (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data
|
[refresh],
|
||||||
uids.push(
|
{
|
||||||
...buddyListV2.flatMap(item => {
|
className: NTClass.NODE_STORE_API,
|
||||||
item.buddyUids.forEach(uid => {
|
cbCmd: ReceiveCmdS.FRIENDS,
|
||||||
categoryMap.set(uid, { categoryId: item.categoryId, categroyName: item.categroyName })
|
afterFirstCmd: false,
|
||||||
})
|
|
||||||
return item.buddyUids
|
|
||||||
}))
|
|
||||||
const data = await session.getProfileService().getCoreAndBaseInfo('nodeStore', uids)
|
|
||||||
return Array.from(data).map(([key, value]) => {
|
|
||||||
const category = categoryMap.get(key)
|
|
||||||
return category ? { ...value, categoryId: category.categoryId, categroyName: category.categroyName } : value
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const data = await invoke<{
|
|
||||||
buddyCategory: CategoryFriend[]
|
|
||||||
userSimpleInfos: Record<string, SimpleInfo>
|
|
||||||
}>(
|
|
||||||
'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']))
|
|
||||||
}
|
}
|
||||||
return Object.values(data.userSimpleInfos)
|
)
|
||||||
.filter(v => v.baseInfo && category.get(v.baseInfo.categoryId)?.buddyUids.includes(v.uid!))
|
return data
|
||||||
.map(value => {
|
|
||||||
return {
|
|
||||||
...value,
|
|
||||||
categoryId: value.baseInfo.categoryId,
|
|
||||||
categroyName: category.get(value.baseInfo.categoryId)?.categroyName
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async isBuddy(uid: string): Promise<boolean> {
|
async isBuddy(uid: string): Promise<boolean> {
|
||||||
|
@ -7,7 +7,8 @@ import {
|
|||||||
GroupRequestOperateTypes,
|
GroupRequestOperateTypes,
|
||||||
GetFileListParam,
|
GetFileListParam,
|
||||||
OnGroupFileInfoUpdateParams,
|
OnGroupFileInfoUpdateParams,
|
||||||
PublishGroupBulletinReq
|
PublishGroupBulletinReq,
|
||||||
|
GroupAllInfo
|
||||||
} from '../types'
|
} from '../types'
|
||||||
import { invoke, NTClass, NTMethod } from '../ntcall'
|
import { invoke, NTClass, NTMethod } from '../ntcall'
|
||||||
import { GeneralCallResult } from '../services'
|
import { GeneralCallResult } from '../services'
|
||||||
@ -104,7 +105,7 @@ export class NTQQGroupApi extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getSingleScreenNotifies(num: number) {
|
async getSingleScreenNotifies(num: number) {
|
||||||
invoke(ReceiveCmdS.GROUP_NOTIFY, [], { classNameIsRegister: true })
|
invoke(ReceiveCmdS.GROUP_NOTIFY, [], { registerEvent: true })
|
||||||
return (await invoke<GroupNotifies>(
|
return (await invoke<GroupNotifies>(
|
||||||
'nodeIKernelGroupService/getSingleScreenNotifies',
|
'nodeIKernelGroupService/getSingleScreenNotifies',
|
||||||
[{ doubt: false, startSeq: '', number: num }, null],
|
[{ doubt: false, startSeq: '', number: num }, null],
|
||||||
@ -272,7 +273,7 @@ export class NTQQGroupApi extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getGroupFileList(groupId: string, fileListForm: GetFileListParam) {
|
async getGroupFileList(groupId: string, fileListForm: GetFileListParam) {
|
||||||
invoke('nodeIKernelMsgListener/onGroupFileInfoUpdate', [], { classNameIsRegister: true })
|
invoke('nodeIKernelMsgListener/onGroupFileInfoUpdate', [], { registerEvent: true })
|
||||||
const data = await invoke<{ fileInfo: OnGroupFileInfoUpdateParams }>(
|
const data = await invoke<{ fileInfo: OnGroupFileInfoUpdateParams }>(
|
||||||
'nodeIKernelRichMediaService/getGroupFileList',
|
'nodeIKernelRichMediaService/getGroupFileList',
|
||||||
[
|
[
|
||||||
@ -326,4 +327,24 @@ export class NTQQGroupApi extends Service {
|
|||||||
}
|
}
|
||||||
}, null])
|
}, null])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getGroupAllInfo(groupCode: string, timeout = 1000) {
|
||||||
|
invoke('nodeIKernelGroupListener/onGroupAllInfoChange', [], { registerEvent: true })
|
||||||
|
return await invoke<{ groupAll: GroupAllInfo }>(
|
||||||
|
'nodeIKernelGroupService/getGroupAllInfo',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
groupCode,
|
||||||
|
source: 4
|
||||||
|
},
|
||||||
|
null
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cbCmd: 'nodeIKernelGroupListener/onGroupAllInfoChange',
|
||||||
|
afterFirstCmd: false,
|
||||||
|
cmdCB: payload => payload.groupAll.groupCode === groupCode,
|
||||||
|
timeout
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ class Core extends Service {
|
|||||||
this.ctx.parallel('nt/friend-request', payload.data.buddyReqs)
|
this.ctx.parallel('nt/friend-request', payload.data.buddyReqs)
|
||||||
})
|
})
|
||||||
|
|
||||||
invoke('nodeIKernelMsgListener/onRecvSysMsg', [], { classNameIsRegister: true })
|
invoke('nodeIKernelMsgListener/onRecvSysMsg', [], { registerEvent: true })
|
||||||
|
|
||||||
registerReceiveHook<{
|
registerReceiveHook<{
|
||||||
msgBuf: number[]
|
msgBuf: number[]
|
||||||
|
@ -98,7 +98,7 @@ interface NTService {
|
|||||||
interface InvokeOptions<ReturnType> {
|
interface InvokeOptions<ReturnType> {
|
||||||
className?: NTClass
|
className?: NTClass
|
||||||
channel?: NTChannel
|
channel?: NTChannel
|
||||||
classNameIsRegister?: boolean
|
registerEvent?: boolean
|
||||||
cbCmd?: string | string[]
|
cbCmd?: string | string[]
|
||||||
cmdCB?: (payload: ReturnType, result: unknown) => boolean
|
cmdCB?: (payload: ReturnType, result: unknown) => boolean
|
||||||
afterFirstCmd?: boolean // 是否在methodName调用完之后再去hook cbCmd
|
afterFirstCmd?: boolean // 是否在methodName调用完之后再去hook cbCmd
|
||||||
@ -115,7 +115,7 @@ export function invoke<
|
|||||||
const timeout = options.timeout ?? 5000
|
const timeout = options.timeout ?? 5000
|
||||||
const afterFirstCmd = options.afterFirstCmd ?? true
|
const afterFirstCmd = options.afterFirstCmd ?? true
|
||||||
let eventName = className + '-' + channel[channel.length - 1]
|
let eventName = className + '-' + channel[channel.length - 1]
|
||||||
if (options.classNameIsRegister) {
|
if (options.registerEvent) {
|
||||||
eventName += '-register'
|
eventName += '-register'
|
||||||
}
|
}
|
||||||
return new Promise<R>((resolve, reject) => {
|
return new Promise<R>((resolve, reject) => {
|
||||||
|
@ -78,3 +78,45 @@ export interface PublishGroupBulletinReq {
|
|||||||
pinned: number
|
pinned: number
|
||||||
confirmRequired: number
|
confirmRequired: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupAllInfo {
|
||||||
|
groupCode: string
|
||||||
|
ownerUid: string
|
||||||
|
groupFlag: number
|
||||||
|
groupFlagExt: number
|
||||||
|
maxMemberNum: number
|
||||||
|
memberNum: number
|
||||||
|
groupOption: number
|
||||||
|
classExt: number
|
||||||
|
groupName: string
|
||||||
|
fingerMemo: string
|
||||||
|
groupQuestion: string
|
||||||
|
certType: number
|
||||||
|
shutUpAllTimestamp: number
|
||||||
|
shutUpMeTimestamp: number //解除禁言时间
|
||||||
|
groupTypeFlag: number
|
||||||
|
privilegeFlag: number
|
||||||
|
groupSecLevel: number
|
||||||
|
groupFlagExt3: number
|
||||||
|
isConfGroup: number
|
||||||
|
isModifyConfGroupFace: number
|
||||||
|
isModifyConfGroupName: number
|
||||||
|
noFigerOpenFlag: number
|
||||||
|
noCodeFingerOpenFlag: number
|
||||||
|
groupFlagExt4: number
|
||||||
|
groupMemo: string
|
||||||
|
cmdUinMsgSeq: number
|
||||||
|
cmdUinJoinTime: number
|
||||||
|
cmdUinUinFlag: number
|
||||||
|
cmdUinMsgMask: number
|
||||||
|
groupSecLevelInfo: number
|
||||||
|
cmdUinPrivilege: number
|
||||||
|
cmdUinFlagEx2: number
|
||||||
|
appealDeadline: number
|
||||||
|
remarkName: number
|
||||||
|
isTop: boolean
|
||||||
|
richFingerMemo: string
|
||||||
|
groupAnswer: string
|
||||||
|
joinGroupAuth: string
|
||||||
|
isAllowModifyConfGroupName: number
|
||||||
|
}
|
||||||
|
@ -4,14 +4,35 @@ import { OB11Entities } from '../../entities'
|
|||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { getBuildVersion } from '@/common/utils'
|
import { getBuildVersion } from '@/common/utils'
|
||||||
|
|
||||||
export class GetFriendWithCategory extends BaseAction<void, OB11User[]> {
|
interface Category {
|
||||||
|
categoryId: number
|
||||||
|
categorySortId: number
|
||||||
|
categoryName: string
|
||||||
|
categoryMbCount: number
|
||||||
|
onlineCount: number
|
||||||
|
buddyList: OB11User[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GetFriendWithCategory extends BaseAction<void, Category[]> {
|
||||||
actionName = ActionName.GetFriendsWithCategory
|
actionName = ActionName.GetFriendsWithCategory
|
||||||
|
|
||||||
protected async _handle() {
|
protected async _handle() {
|
||||||
if (getBuildVersion() >= 26702) {
|
if (getBuildVersion() < 26702) {
|
||||||
return OB11Entities.friendsV2(await this.ctx.ntFriendApi.getBuddyV2ExWithCate(true))
|
|
||||||
} else {
|
|
||||||
throw new Error('this ntqq version not support, must be 26702 or later')
|
throw new Error('this ntqq version not support, must be 26702 or later')
|
||||||
}
|
}
|
||||||
|
const data = await this.ctx.ntFriendApi.getBuddyV2WithCate(true)
|
||||||
|
return data.buddyCategory.map(item => {
|
||||||
|
return {
|
||||||
|
categoryId: item.categoryId,
|
||||||
|
categorySortId: item.categorySortId,
|
||||||
|
categoryName: item.categroyName,
|
||||||
|
categoryMbCount: item.categroyMbCount,
|
||||||
|
onlineCount: item.onlineCount,
|
||||||
|
buddyList: item.buddyUids.map(uid => {
|
||||||
|
const info = data.userSimpleInfos[uid]
|
||||||
|
return OB11Entities.friendV2(info)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ export namespace OB11Entities {
|
|||||||
}
|
}
|
||||||
else if (element.textElement) {
|
else if (element.textElement) {
|
||||||
const text = element.textElement.content
|
const text = element.textElement.content
|
||||||
if (!text.trim()) {
|
if (!text) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
messageSegment = {
|
messageSegment = {
|
||||||
@ -359,15 +359,15 @@ export namespace OB11Entities {
|
|||||||
}
|
}
|
||||||
if (messageSegment) {
|
if (messageSegment) {
|
||||||
const cqCode = encodeCQCode(messageSegment)
|
const cqCode = encodeCQCode(messageSegment)
|
||||||
if (messagePostFormat === 'string') {
|
if (messagePostFormat === 'array') {
|
||||||
(resMsg.message as string) += cqCode
|
|
||||||
} else {
|
|
||||||
(resMsg.message as OB11MessageData[]).push(messageSegment)
|
(resMsg.message as OB11MessageData[]).push(messageSegment)
|
||||||
}
|
}
|
||||||
resMsg.raw_message += cqCode
|
resMsg.raw_message += cqCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resMsg.raw_message = resMsg.raw_message.trim()
|
if (messagePostFormat === 'string') {
|
||||||
|
resMsg.message = resMsg.raw_message
|
||||||
|
}
|
||||||
return resMsg
|
return resMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +436,7 @@ export namespace OB11Entities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (groupElement.type === TipGroupElementType.Ban) {
|
else if (groupElement.type === TipGroupElementType.Ban) {
|
||||||
ctx.logger.info('收到群群员禁言提示', groupElement)
|
ctx.logger.info('收到群成员禁言提示', groupElement)
|
||||||
const memberUid = groupElement.shutUp?.member.uid
|
const memberUid = groupElement.shutUp?.member.uid
|
||||||
const adminUid = groupElement.shutUp?.admin.uid
|
const adminUid = groupElement.shutUp?.admin.uid
|
||||||
let memberUin: string = ''
|
let memberUin: string = ''
|
||||||
@ -649,23 +649,20 @@ export namespace OB11Entities {
|
|||||||
return friends.map(friend)
|
return friends.map(friend)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function friendsV2(friends: FriendV2[]): OB11User[] {
|
export function friendV2(raw: FriendV2): OB11User {
|
||||||
const data: OB11User[] = []
|
return {
|
||||||
for (const friend of friends) {
|
...omit(raw.baseInfo, ['richBuffer', 'phoneNum']),
|
||||||
const sexValue = sex(friend.baseInfo.sex!)
|
...omit(raw.coreInfo, ['nick']),
|
||||||
data.push({
|
user_id: parseInt(raw.coreInfo.uin),
|
||||||
...omit(friend.baseInfo, ['richBuffer']),
|
nickname: raw.coreInfo.nick,
|
||||||
...friend.coreInfo,
|
remark: raw.coreInfo.remark || raw.coreInfo.nick,
|
||||||
user_id: parseInt(friend.coreInfo.uin),
|
sex: sex(raw.baseInfo.sex),
|
||||||
nickname: friend.coreInfo.nick,
|
level: 0
|
||||||
remark: friend.coreInfo.nick,
|
|
||||||
sex: sexValue,
|
|
||||||
level: 0,
|
|
||||||
categroyName: friend.categroyName,
|
|
||||||
categoryId: friend.categoryId
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return data
|
}
|
||||||
|
|
||||||
|
export function friendsV2(raw: FriendV2[]): OB11User[] {
|
||||||
|
return raw.map(friendV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
export function groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
||||||
|
@ -248,8 +248,16 @@ export async function sendMsg(
|
|||||||
sendElements: SendMessageElement[],
|
sendElements: SendMessageElement[],
|
||||||
deleteAfterSentFiles: string[]
|
deleteAfterSentFiles: string[]
|
||||||
) {
|
) {
|
||||||
|
if (peer.chatType === ChatType.Group) {
|
||||||
|
const info = await ctx.ntGroupApi.getGroupAllInfo(peer.peerUid)
|
||||||
|
.catch(() => undefined)
|
||||||
|
const shutUpMeTimestamp = info?.groupAll.shutUpMeTimestamp
|
||||||
|
if (shutUpMeTimestamp && shutUpMeTimestamp * 1000 > Date.now()) {
|
||||||
|
throw new Error('当前处于被禁言状态')
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!sendElements.length) {
|
if (!sendElements.length) {
|
||||||
throw '消息体无法解析,请检查是否发送了不支持的消息类型'
|
throw new Error('消息体无法解析,请检查是否发送了不支持的消息类型')
|
||||||
}
|
}
|
||||||
// 计算发送的文件大小
|
// 计算发送的文件大小
|
||||||
let totalSize = 0
|
let totalSize = 0
|
||||||
|
@ -1 +1 @@
|
|||||||
export const version = '3.33.7'
|
export const version = '3.33.8'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user