Compare commits

..

7 Commits

Author SHA1 Message Date
idranme
457ffc0922 Merge pull request #461 from LLOneBot/dev
release: 4.0.2
2024-10-08 21:26:39 +08:00
idranme
e3a2303e45 chore: bump versions 2024-10-08 21:25:23 +08:00
idranme
8465c47d41 fix 2024-10-08 21:22:04 +08:00
idranme
41822eb052 Merge pull request #460 from LLOneBot/dev
release: 4.0.1
2024-10-08 20:46:09 +08:00
idranme
b5578d6278 chore: bump versions 2024-10-08 20:43:56 +08:00
idranme
fecb4c4655 feat(onebot): delete_friend API 2024-10-08 20:40:02 +08:00
idranme
c82b849ead fix 2024-10-08 20:07:12 +08:00
13 changed files with 61 additions and 22 deletions

View File

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

View File

@@ -62,9 +62,10 @@ class Store extends Service {
}
createMsgShortId(peer: Peer, msgId: string): number {
// OneBot 11 要求 message_id 为 int32
const cacheKey = `${msgId}|${peer.chatType}|${peer.peerUid}`
const hash = createHash('md5').update(cacheKey).digest()
hash[0] &= 0x7f //设置第一个bit为0 保证shortId为正数
hash[0] &= 0x7f //保证shortId为正数
const shortId = hash.readInt32BE()
this.cache.set(cacheKey, shortId)
this.ctx.database.upsert('message', [{

View File

@@ -16,7 +16,7 @@ import path from 'node:path'
import { existsSync } from 'node:fs'
import { ReceiveCmdS } from '../hook'
import { RkeyManager } from '@/ntqqapi/helper/rkey'
import { OnRichMediaDownloadCompleteParams, Peer } from '@/ntqqapi/types/msg'
import { RichMediaDownloadCompleteNotify, Peer } from '@/ntqqapi/types/msg'
import { calculateFileMD5 } from '@/common/utils/file'
import { copyFile, stat, unlink } from 'node:fs/promises'
import { Time } from 'cosmokit'
@@ -113,7 +113,7 @@ export class NTQQFileApi extends Service {
return sourcePath
}
}
const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>(
const data = await invoke<{ notifyInfo: RichMediaDownloadCompleteNotify }>(
'nodeIKernelMsgService/downloadRichMedia',
[{
getReq: {
@@ -185,7 +185,7 @@ export class NTQQFileApi extends Service {
}
async downloadFileForModelId(peer: Peer, fileModelId: string, timeout = 2 * Time.minute) {
const data = await invoke<{ notifyInfo: OnRichMediaDownloadCompleteParams }>(
const data = await invoke<{ notifyInfo: RichMediaDownloadCompleteNotify }>(
'nodeIKernelRichMediaService/downloadFileForModelId',
[{
peer,

View File

@@ -116,4 +116,14 @@ export class NTQQFriendApi extends Service {
remarkParams: { uid, remark }
}])
}
async delBuddy(friendUid: string) {
return await invoke('nodeIKernelBuddyService/delBuddy', [{
delInfo: {
friendUid,
tempBlock: false,
tempBothDel: true
}
}])
}
}

View File

@@ -55,7 +55,7 @@ export class NTQQGroupApi extends Service {
}
async getGroupMember(groupCode: string, uid: string, forceUpdate = false) {
invoke('nodeIKernelGroupListener/onMemberInfoChange', [], {
await invoke('nodeIKernelGroupListener/onMemberInfoChange', [], {
registerEvent: true
})

View File

@@ -37,6 +37,7 @@ export class NTQQMsgApi extends Service {
}
async activateChatAndGetHistory(peer: Peer, cnt: number) {
// 消息从旧到新
return await invoke(NTMethod.ACTIVE_CHAT_HISTORY, [{ peer, cnt, msgId: '0', queryOrder: true }])
}

View File

@@ -124,10 +124,15 @@ class Core extends Service {
activatedPeerUids.push(contact.id)
const peer = { peerUid: contact.id, chatType: contact.chatType }
if (contact.chatType === ChatType.TempC2CFromGroup) {
this.ctx.ntMsgApi.activateChatAndGetHistory(peer, 1).then(res => {
const lastTempMsg = res.msgList[0]
if (Date.now() / 1000 - Number(lastTempMsg?.msgTime) < 5) {
this.ctx.parallel('nt/message-created', lastTempMsg!)
this.ctx.ntMsgApi.activateChatAndGetHistory(peer, 2).then(res => {
for (const msg of res.msgList) {
if (Date.now() / 1000 - Number(msg.msgTime) > 3) {
continue
}
if (msg.senderUin && msg.senderUin !== '0') {
this.ctx.store.addMsgCache(msg)
}
this.ctx.parallel('nt/message-created', msg)
}
})
} else {

View File

@@ -476,7 +476,7 @@ export interface MessageElement {
actionBarElement?: unknown
}
export interface OnRichMediaDownloadCompleteParams {
export interface RichMediaDownloadCompleteNotify {
fileModelId: string
msgElementId: string
msgId: string

View File

@@ -0,0 +1,21 @@
import { BaseAction, Schema } from '../BaseAction'
import { ActionName } from '../types'
interface Payload {
user_id: number | string
}
export class DeleteFriend extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_DeleteFriend
payloadSchema = Schema.object({
user_id: Schema.union([Number, String]).required()
})
protected async _handle(payload: Payload) {
const uin = payload.user_id.toString()
const uid = await this.ctx.ntUserApi.getUidByUin(uin)
if (!uid) throw new Error('无法获取用户信息')
await this.ctx.ntFriendApi.delBuddy(uid)
return null
}
}

View File

@@ -72,6 +72,7 @@ import { UploadPrivateFile } from './go-cqhttp/UploadPrivateFile'
import { GetGroupFileUrl } from './go-cqhttp/GetGroupFileUrl'
import { GetGroupNotice } from './go-cqhttp/GetGroupNotice'
import { GetRobotUinRange } from './llonebot/GetRobotUinRange'
import { DeleteFriend } from './go-cqhttp/DeleteFriend'
export function initActionMap(adapter: Adapter) {
const actionHandlers = [
@@ -149,6 +150,7 @@ export function initActionMap(adapter: Adapter) {
new GetGroupFilesByFolder(adapter),
new GetGroupFileUrl(adapter),
new GetGroupNotice(adapter),
new DeleteFriend(adapter),
]
const actionMap = new Map<string, BaseAction<any, unknown>>()
for (const action of actionHandlers) {

View File

@@ -85,4 +85,5 @@ export enum ActionName {
GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder',
GoCQHTTP_GetGroupFileUrl = 'get_group_file_url',
GoCQHTTP_GetGroupNotice = '_get_group_notice',
GoCQHTTP_DeleteFriend = 'delete_friend',
}

View File

@@ -33,13 +33,6 @@ function decodeMessageUser(data: NT.RawMessage) {
}
}
function decodeMessageMember(user: Universal.User, data: NT.RawMessage) {
return {
user: user,
nick: data.sendMemberName || data.sendNickName
}
}
async function decodeElement(ctx: Context, data: NT.RawMessage, quoted = false) {
const buffer: h[] = []
for (const v of data.elements) {
@@ -162,11 +155,13 @@ export async function decodeMessage(
}
message.user = decodeMessageUser(data)
message.created_at = +data.msgTime * 1000
if (message.channel.type === Universal.Channel.Type.DIRECT) {
if (!message.user.name) {
const info = await ctx.ntUserApi.getUserSimpleInfo(data.senderUid)
message.channel.name = info.nick
message.user.name = info.nick
message.user.nick = info.remark || info.nick
if (message.channel.type === Universal.Channel.Type.DIRECT) {
message.channel.name = info.nick
}
}
if (guildId) {
message.guild = {
@@ -174,7 +169,10 @@ export async function decodeMessage(
name: data.peerName,
avatar: `https://p.qlogo.cn/gh/${guildId}/${guildId}/640`
}
message.member = decodeMessageMember(message.user, data)
message.member = {
user: message.user,
nick: data.sendMemberName || message.user.name
}
}
return message

View File

@@ -1 +1 @@
export const version = '4.0.0'
export const version = '4.0.2'