Merge pull request #452 from LLOneBot/dev

release: 3.33.10
This commit is contained in:
idranme 2024-09-28 14:40:11 +08:00 committed by GitHub
commit 36d990e328
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 165 additions and 27 deletions

View File

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

View File

@ -32,7 +32,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/express": "^4.17.21", "@types/express": "^5.0.0",
"@types/fluent-ffmpeg": "^2.1.26", "@types/fluent-ffmpeg": "^2.1.26",
"@types/node": "^20.14.15", "@types/node": "^20.14.15",
"@types/ws": "^8.5.12", "@types/ws": "^8.5.12",
@ -40,7 +40,7 @@
"electron-vite": "^2.3.0", "electron-vite": "^2.3.0",
"protobufjs-cli": "^1.1.3", "protobufjs-cli": "^1.1.3",
"typescript": "^5.6.2", "typescript": "^5.6.2",
"vite": "^5.4.7", "vite": "^5.4.8",
"vite-plugin-cp": "^4.0.8" "vite-plugin-cp": "^4.0.8"
}, },
"packageManager": "yarn@4.5.0" "packageManager": "yarn@4.5.0"

View File

@ -8,7 +8,8 @@ import {
GetFileListParam, GetFileListParam,
PublishGroupBulletinReq, PublishGroupBulletinReq,
GroupAllInfo, GroupAllInfo,
GroupFileInfo GroupFileInfo,
GroupBulletinListResult
} from '../types' } from '../types'
import { invoke, NTClass, NTMethod } from '../ntcall' import { invoke, NTClass, NTMethod } from '../ntcall'
import { GeneralCallResult } from '../services' import { GeneralCallResult } from '../services'
@ -347,4 +348,33 @@ export class NTQQGroupApi extends Service {
} }
) )
} }
async getGroupBulletinList(groupCode: string) {
invoke('nodeIKernelGroupListener/onGetGroupBulletinListResult', [], { registerEvent: true })
const ntUserApi = this.ctx.get('ntUserApi')!
const psKey = (await ntUserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!
return await invoke<{
groupCode: string
context: string
result: GroupBulletinListResult
}>(
'nodeIKernelGroupService/getGroupBulletinList',
[{
groupCode,
psKey,
context: '',
req: {
startIndex: -1,
num: 20,
needInstructionsForJoinGroup: 1,
needPublisherInfo: 1
}
}],
{
cbCmd: 'nodeIKernelGroupListener/onGetGroupBulletinListResult',
cmdCB: payload => payload.groupCode === groupCode,
afterFirstCmd: false
}
)
}
} }

View File

@ -22,9 +22,9 @@ export interface Group {
hasModifyConfGroupName: boolean hasModifyConfGroupName: boolean
remarkName: string remarkName: string
hasMemo: boolean hasMemo: boolean
groupShutupExpireTime: string //"0", groupShutupExpireTime: string
personShutupExpireTime: string //"0", personShutupExpireTime: string
discussToGroupUin: string //"0", discussToGroupUin: string
discussToGroupMaxMsgSeq: number discussToGroupMaxMsgSeq: number
discussToGroupTime: number discussToGroupTime: number
groupFlagExt: number //1073938496, groupFlagExt: number //1073938496,
@ -32,8 +32,8 @@ export interface Group {
groupCreditLevel: number //0, groupCreditLevel: number //0,
groupFlagExt3: number //0, groupFlagExt3: number //0,
groupOwnerId: { groupOwnerId: {
memberUin: string //"0", memberUin: string
memberUid: string //"u_fbf8N7aeuZEnUiJAbQ9R8Q" memberUid: string
} }
members: GroupMember[] // 原始数据是没有这个的,为了方便自己加了这个字段 members: GroupMember[] // 原始数据是没有这个的,为了方便自己加了这个字段
createTime: string createTime: string
@ -120,3 +120,55 @@ export interface GroupAllInfo {
joinGroupAuth: string joinGroupAuth: string
isAllowModifyConfGroupName: number isAllowModifyConfGroupName: number
} }
export interface GroupBulletinListResult {
groupCode: string
srvCode: number
readOnly: number
role: number
inst: unknown[]
feeds: {
uin: string
feedId: string
publishTime: string
msg: {
text: string
textFace: string
pics: {
id: string
width: number
height: number
}[]
title: string
}
type: number
fn: number
cn: number
vn: number
settings: {
isShowEditCard: number
remindTs: number
tipWindowType: number
confirmRequired: number
}
pinned: number
readNum: number
is_read: number
is_all_confirm: number
}[]
groupInfo: {
groupCode: string
classId: number
}
gln: number
tst: number
publisherInfos: {
uin: string
nick: string
avatar: string
}[]
server_time: string
svrt: string
nextIndex: number
jointime: string
}

View File

@ -0,0 +1,48 @@
import { BaseAction, Schema } from '../BaseAction'
import { ActionName } from '../types'
interface Payload {
group_id: number | string
}
interface Notice {
sender_id: number
publish_time: number
message: {
text: string
images: {
height: string
width: string
id: string
}[]
}
}
export class GetGroupNotice extends BaseAction<Payload, Notice[]> {
actionName = ActionName.GoCQHTTP_GetGroupNotice
payloadSchema = Schema.object({
group_id: Schema.union([Number, String]).required()
})
protected async _handle(payload: Payload) {
const data = await this.ctx.ntGroupApi.getGroupBulletinList(payload.group_id.toString())
const result: Notice[] = []
for (const feed of data.result.feeds) {
result.push({
sender_id: +feed.uin,
publish_time: +feed.publishTime,
message: {
text: feed.msg.text,
images: feed.msg.pics.map(image => {
return {
height: String(image.height),
width: String(image.width),
id: image.id
}
})
}
})
}
return result
}
}

View File

@ -10,7 +10,8 @@ import { convertMessage2List, createSendElements, sendMsg, createPeer, CreatePee
interface Payload { interface Payload {
user_id?: string | number user_id?: string | number
group_id?: string | number group_id?: string | number
messages: OB11MessageNode[] messages?: OB11MessageNode[]
message?: OB11MessageNode[]
message_type?: 'group' | 'private' message_type?: 'group' | 'private'
} }
@ -20,15 +21,20 @@ interface Response {
} }
export class SendForwardMsg extends BaseAction<Payload, Response> { export class SendForwardMsg extends BaseAction<Payload, Response> {
actionName = ActionName.GoCQHTTP_SendForwardMsg actionName = ActionName.SendForwardMsg
payloadSchema = Schema.object({ payloadSchema = Schema.object({
user_id: Schema.union([Number, String]), user_id: Schema.union([Number, String]),
group_id: Schema.union([Number, String]), group_id: Schema.union([Number, String]),
messages: Schema.array(Schema.any()).required(), messages: Schema.array(Schema.any()),
message: Schema.array(Schema.any()),
message_type: Schema.union(['group', 'private']) message_type: Schema.union(['group', 'private'])
}) })
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const messages = payload.messages ?? payload.message
if (!messages) {
throw new Error('未指定消息内容')
}
let contextMode = CreatePeerMode.Normal let contextMode = CreatePeerMode.Normal
if (payload.message_type === 'group') { if (payload.message_type === 'group') {
contextMode = CreatePeerMode.Group contextMode = CreatePeerMode.Group
@ -36,7 +42,7 @@ export class SendForwardMsg extends BaseAction<Payload, Response> {
contextMode = CreatePeerMode.Private contextMode = CreatePeerMode.Private
} }
const peer = await createPeer(this.ctx, payload, contextMode) const peer = await createPeer(this.ctx, payload, contextMode)
const msg = await this.handleForwardNode(peer, payload.messages) const msg = await this.handleForwardNode(peer, messages)
const msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId) const msgShortId = this.ctx.store.createMsgShortId({ chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)
return { message_id: msgShortId } return { message_id: msgShortId }
} }

View File

@ -4,7 +4,7 @@ import { ActionName } from '../types'
interface Payload { interface Payload {
group_id: number | string group_id: number | string
user_id: number | string user_id: number | string
duration: number duration: number | string
} }
export default class SetGroupBan extends BaseAction<Payload, null> { export default class SetGroupBan extends BaseAction<Payload, null> {
@ -12,7 +12,7 @@ export default class SetGroupBan extends BaseAction<Payload, null> {
payloadSchema = Schema.object({ payloadSchema = Schema.object({
group_id: Schema.union([Number, String]).required(), group_id: Schema.union([Number, String]).required(),
user_id: Schema.union([Number, String]).required(), user_id: Schema.union([Number, String]).required(),
duration: Schema.number().default(30 * 60) duration: Schema.union([Number, String]).default(30 * 60)
}) })
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
@ -21,7 +21,7 @@ export default class SetGroupBan extends BaseAction<Payload, null> {
const uid = await this.ctx.ntUserApi.getUidByUin(uin, groupCode) const uid = await this.ctx.ntUserApi.getUidByUin(uin, groupCode)
if (!uid) throw new Error('无法获取用户信息') if (!uid) throw new Error('无法获取用户信息')
await this.ctx.ntGroupApi.banMember(groupCode, [ await this.ctx.ntGroupApi.banMember(groupCode, [
{ uid, timeStamp: payload.duration }, { uid, timeStamp: +payload.duration },
]) ])
return null return null
} }

View File

@ -70,6 +70,7 @@ import { GetFriendWithCategory } from './llonebot/GetFriendWithCategory'
import { UploadGroupFile } from './go-cqhttp/UploadGroupFile' import { UploadGroupFile } from './go-cqhttp/UploadGroupFile'
import { UploadPrivateFile } from './go-cqhttp/UploadPrivateFile' import { UploadPrivateFile } from './go-cqhttp/UploadPrivateFile'
import { GetGroupFileUrl } from './go-cqhttp/GetGroupFileUrl' import { GetGroupFileUrl } from './go-cqhttp/GetGroupFileUrl'
import { GetGroupNotice } from './go-cqhttp/GetGroupNotice'
export function initActionMap(adapter: Adapter) { export function initActionMap(adapter: Adapter) {
const actionHandlers = [ const actionHandlers = [
@ -144,7 +145,8 @@ export function initActionMap(adapter: Adapter) {
new GetGroupRootFiles(adapter), new GetGroupRootFiles(adapter),
new SendGroupNotice(adapter), new SendGroupNotice(adapter),
new GetGroupFilesByFolder(adapter), new GetGroupFilesByFolder(adapter),
new GetGroupFileUrl(adapter) new GetGroupFileUrl(adapter),
new GetGroupNotice(adapter),
] ]
const actionMap = new Map<string, BaseAction<any, unknown>>() const actionMap = new Map<string, BaseAction<any, unknown>>()
for (const action of actionHandlers) { for (const action of actionHandlers) {

View File

@ -24,6 +24,7 @@ export enum ActionName {
FetchEmojiLike = 'fetch_emoji_like', FetchEmojiLike = 'fetch_emoji_like',
FetchCustomFace = 'fetch_custom_face', FetchCustomFace = 'fetch_custom_face',
GetFriendMsgHistory = 'get_friend_msg_history', GetFriendMsgHistory = 'get_friend_msg_history',
SendForwardMsg = 'send_forward_msg',
// onebot 11 // onebot 11
SendLike = 'send_like', SendLike = 'send_like',
GetLoginInfo = 'get_login_info', GetLoginInfo = 'get_login_info',
@ -58,7 +59,6 @@ export enum ActionName {
ForwardFriendSingleMsg = 'forward_friend_single_msg', ForwardFriendSingleMsg = 'forward_friend_single_msg',
ForwardGroupSingleMsg = 'forward_group_single_msg', ForwardGroupSingleMsg = 'forward_group_single_msg',
// 以下为go-cqhttp api // 以下为go-cqhttp api
GoCQHTTP_SendForwardMsg = 'send_forward_msg',
GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg', GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg',
GoCQHTTP_SendPrivateForwardMsg = 'send_private_forward_msg', GoCQHTTP_SendPrivateForwardMsg = 'send_private_forward_msg',
GoCQHTTP_GetStrangerInfo = 'get_stranger_info', GoCQHTTP_GetStrangerInfo = 'get_stranger_info',
@ -82,5 +82,6 @@ export enum ActionName {
GoCQHTTP_GetGroupRootFiles = 'get_group_root_files', GoCQHTTP_GetGroupRootFiles = 'get_group_root_files',
GoCQHTTP_SendGroupNotice = '_send_group_notice', GoCQHTTP_SendGroupNotice = '_send_group_notice',
GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder', GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder',
GoCQHTTP_GetGroupFileUrl = 'get_group_file_url' GoCQHTTP_GetGroupFileUrl = 'get_group_file_url',
GoCQHTTP_GetGroupNotice = '_get_group_notice',
} }

View File

@ -5,7 +5,6 @@ import {
GroupNotifyType, GroupNotifyType,
RawMessage, RawMessage,
BuddyReqType, BuddyReqType,
Peer,
FriendRequest, FriendRequest,
GroupMember, GroupMember,
GroupMemberRole, GroupMemberRole,

View File

@ -1,7 +1,7 @@
import http from 'node:http' import http from 'node:http'
import cors from 'cors' import cors from 'cors'
import crypto from 'node:crypto' import crypto from 'node:crypto'
import express, { Express, Request, Response } from 'express' import express, { Express, Request, Response, NextFunction } from 'express'
import { BaseAction } from '../action/BaseAction' import { BaseAction } from '../action/BaseAction'
import { Context } from 'cordis' import { Context } from 'cordis'
import { llonebotError, selfInfo } from '@/common/globalVars' import { llonebotError, selfInfo } from '@/common/globalVars'
@ -76,7 +76,7 @@ class OB11Http {
Object.assign(this.config, config) Object.assign(this.config, config)
} }
private authorize(req: Request, res: Response, next: () => void) { private authorize(req: Request, res: Response, next: NextFunction) {
const serverToken = this.config.token const serverToken = this.config.token
if (!serverToken) return next() if (!serverToken) return next()
@ -95,12 +95,13 @@ class OB11Http {
} }
if (clientToken !== serverToken) { if (clientToken !== serverToken) {
return res.status(403).json({ message: 'token verify failed!' }) res.status(403).json({ message: 'token verify failed!' })
} } else {
next() next()
} }
}
private async handleRequest(req: Request, res: Response, next: () => void) { private async handleRequest(req: Request, res: Response, next: NextFunction) {
if (req.path === '/') return next() if (req.path === '/') return next()
let payload = req.body let payload = req.body
if (req.method === 'GET') { if (req.method === 'GET') {

View File

@ -1 +1 @@
export const version = '3.33.9' export const version = '3.33.10'

View File

@ -4,7 +4,6 @@
"module": "CommonJS", "module": "CommonJS",
"outDir": "./dist", "outDir": "./dist",
"strict": true, "strict": true,
"isolatedModules": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"experimentalDecorators": true, "experimentalDecorators": true,