diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..d6dc7d8 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,14 @@ +# 3.24.0 + +## 修复 + +* 修复图片rkey导致链接失效的问题 +* 修复/get_image, /get_file 无法获取图片的问题 +* 修复上报他人管理员被取消通知 + +## 新增 + +* 新增表情回应发送和上报 +* 新增商城表情发送,和上报 url +* 新增转发单条消息接口 `forward_friend_single_msg`, `forward_group_single_msg` +* 新增新增好友事件 \ No newline at end of file diff --git a/manifest.json b/manifest.json index d49a0d4..7f133a7 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { "manifest_version": 4, "type": "extension", - "name": "LLOneBot v3.23.0", + "name": "LLOneBot v3.24.0", "slug": "LLOneBot", "description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发, 不支持商店在线更新", - "version": "3.23.0", + "version": "3.24.0", "icon": "./icon.jpg", "authors": [ { @@ -20,10 +20,14 @@ "name": "LLOneBot.zip" } }, - "platform": ["win32", "linux", "darwin"], + "platform": [ + "win32", + "linux", + "darwin" + ], "injects": { "renderer": "./renderer/index.js", "main": "./main/main.cjs", "preload": "./preload/preload.cjs" } -} +} \ No newline at end of file diff --git a/src/common/data.ts b/src/common/data.ts index 8c03020..0bd6744 100644 --- a/src/common/data.ts +++ b/src/common/data.ts @@ -3,6 +3,7 @@ import { type FileCache, type LLOneBotError } from './types' import { NTQQGroupApi } from '../ntqqapi/api/group' import { log } from './utils/log' import { isNumeric } from './utils/helper' +import { NTQQFriendApi } from '../ntqqapi/api' export const selfInfo: SelfInfo = { uid: '', @@ -24,14 +25,17 @@ export async function getFriend(uinOrUid: string): Promise { let filterKey = isNumeric(uinOrUid.toString()) ? 'uin' : 'uid' let filterValue = uinOrUid let friend = friends.find((friend) => friend[filterKey] === filterValue.toString()) - // if (!friend) { - // try { - // friends = (await NTQQApi.getFriends(true)) - // friend = friends.find(friend => friend[filterKey] === filterValue.toString()) - // } catch (e) { - // // log("刷新好友列表失败", e.stack.toString()) - // } - // } + if (!friend) { + try { + const _friends = (await NTQQFriendApi.getFriends(true)) + friend = _friends.find(friend => friend[filterKey] === filterValue.toString()) + if (friend){ + friends.push(friend) + } + } catch (e) { + log("刷新好友列表失败", e.stack.toString()) + } + } return friend } @@ -44,7 +48,8 @@ export async function getGroup(qq: string): Promise { if (group) { groups.push(group) } - } catch (e) {} + } catch (e) { + } } return group } diff --git a/src/main/main.ts b/src/main/main.ts index 14d0cf8..854ae3b 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -157,6 +157,7 @@ function onLoad() { const { debug, reportSelfMessage } = getConfigUtil().getConfig() for (let message of msgList) { // 过滤启动之前的消息 + // log('收到新消息', message); if (parseInt(message.msgTime) < startTime / 1000) { continue } @@ -191,6 +192,12 @@ function onLoad() { postOB11Event(groupEvent) } }) + OB11Constructor.FriendAddEvent(message).then((friendAddEvent) => { + if (friendAddEvent) { + // log("post friend add event", friendAddEvent); + postOB11Event(friendAddEvent) + } + }) } } @@ -219,7 +226,7 @@ function onLoad() { }) registerReceiveHook<{ msgList: Array }>([ReceiveCmdS.UPDATE_MSG], async (payload) => { for (const message of payload.msgList) { - // log("message update", message.sendStatus, message.msgId, message.msgSeq) + // log("message update", message) if (message.recallTime != '0') { //todo: 这个判断方法不太好,应该使用灰色消息元素来判断 // 撤回消息上报 @@ -304,7 +311,7 @@ function onLoad() { // if (notify.user2.uid) { // member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid); // } - if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET].includes(notify.type)) { + if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(notify.type)) { const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid) log('有管理员变动通知') refreshGroupMembers(notify.group.groupCode).then() @@ -314,7 +321,7 @@ function onLoad() { if (member1) { log('变动管理员获取成功') groupAdminNoticeEvent.user_id = parseInt(member1.uin) - groupAdminNoticeEvent.sub_type = notify.type == GroupNotifyTypes.ADMIN_UNSET ? 'unset' : 'set' + groupAdminNoticeEvent.sub_type = [GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(notify.type) ? 'unset' : 'set' // member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal; postOB11Event(groupAdminNoticeEvent, true) } else { diff --git a/src/ntqqapi/api/friend.ts b/src/ntqqapi/api/friend.ts index 1604c29..cfa2daf 100644 --- a/src/ntqqapi/api/friend.ts +++ b/src/ntqqapi/api/friend.ts @@ -2,6 +2,7 @@ import { Friend, FriendRequest } from '../types' import { ReceiveCmdS } from '../hook' import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall' import { friendRequests } from '../../common/data' +import { log } from '../../common/utils' export class NTQQFriendApi { static async getFriends(forced = false) { @@ -16,7 +17,9 @@ export class NTQQFriendApi { methodName: NTQQApiMethod.FRIENDS, args: [{ force_update: forced }, undefined], cbCmd: ReceiveCmdS.FRIENDS, + afterFirstCmd: false, }) + // log('获取好友列表', data) let _friends: Friend[] = [] for (const fData of data.data) { _friends.push(...fData.buddyList) diff --git a/src/ntqqapi/constructor.ts b/src/ntqqapi/constructor.ts index 6d7c424..e8b9b8b 100644 --- a/src/ntqqapi/constructor.ts +++ b/src/ntqqapi/constructor.ts @@ -23,6 +23,8 @@ import { defaultVideoThumb, getVideoInfo } from '../common/utils/video' import { encodeSilk } from '../common/utils/audio' import { isNull } from '../common/utils' +export const mFaceCache = new Map(); // emojiId -> faceName + export class SendMsgElementConstructor { static poke(groupCode: string, uin: string) { return null @@ -117,7 +119,15 @@ export class SendMsgElementConstructor { } static async video(filePath: string, fileName: string = '', diyThumbPath: string = ''): Promise { + try{ + await fs.stat(filePath) + }catch (e) { + throw `文件${filePath}异常,不存在` + } + log("复制视频到QQ目录", filePath) let { fileName: _fileName, path, fileSize, md5 } = await NTQQFileApi.uploadFile(filePath, ElementType.VIDEO) + + log("复制视频到QQ目录完成", path) if (fileSize === 0) { throw '文件异常,大小为0' } @@ -184,7 +194,7 @@ export class SendMsgElementConstructor { }) let thumbPath = new Map() const _thumbPath = await createThumb - log('生成缩略图', _thumbPath) + log('生成视频缩略图', _thumbPath) const thumbSize = (await fs.stat(_thumbPath)).size // log("生成缩略图", _thumbPath) thumbPath.set(0, _thumbPath) @@ -273,7 +283,7 @@ export class SendMsgElementConstructor { emojiPackageId, emojiId, key, - faceName + faceName: faceName || mFaceCache.get(emojiId) || '[商城表情]', }, } } diff --git a/src/ntqqapi/types/msg.ts b/src/ntqqapi/types/msg.ts index 6978f24..f21d008 100644 --- a/src/ntqqapi/types/msg.ts +++ b/src/ntqqapi/types/msg.ts @@ -372,6 +372,8 @@ export interface MultiForwardMsgElement { export interface RawMessage { msgId: string + msgType: number + subMsgType: number msgShortId?: number // 自己维护的消息id msgTime: string // 时间戳,秒 msgSeq: string diff --git a/src/ntqqapi/types/notify.ts b/src/ntqqapi/types/notify.ts index 2da2f68..c568dfc 100644 --- a/src/ntqqapi/types/notify.ts +++ b/src/ntqqapi/types/notify.ts @@ -5,7 +5,8 @@ export enum GroupNotifyTypes { ADMIN_SET = 8, KICK_MEMBER = 9, MEMBER_EXIT = 11, // 主动退出 - ADMIN_UNSET = 12, + ADMIN_UNSET = 12, // 我被取消管理员 + ADMIN_UNSET_OTHER = 13, // 其他人取消管理员 } export interface GroupNotifies { diff --git a/src/onebot11/action/group/GetGroupList.ts b/src/onebot11/action/group/GetGroupList.ts index f27ef0c..b5c2ae5 100644 --- a/src/onebot11/action/group/GetGroupList.ts +++ b/src/onebot11/action/group/GetGroupList.ts @@ -7,7 +7,7 @@ import { NTQQGroupApi } from '../../../ntqqapi/api' import { log } from '../../../common/utils' interface Payload { - no_cache: boolean + no_cache: boolean | string } class GetGroupList extends BaseAction { @@ -16,11 +16,11 @@ class GetGroupList extends BaseAction { protected async _handle(payload: Payload) { if ( groups.length === 0 - // || payload.no_cache === true + || payload?.no_cache === true || payload?.no_cache === 'true' ) { try { const groups = await NTQQGroupApi.getGroups(true) - // log("get groups", groups) + log("强制刷新群列表, 数量:", groups.length) return OB11Constructor.groups(groups) } catch (e) {} } diff --git a/src/onebot11/action/group/GetGroupMemberList.ts b/src/onebot11/action/group/GetGroupMemberList.ts index da7555c..2c541f8 100644 --- a/src/onebot11/action/group/GetGroupMemberList.ts +++ b/src/onebot11/action/group/GetGroupMemberList.ts @@ -4,9 +4,11 @@ import { OB11Constructor } from '../../constructor' import BaseAction from '../BaseAction' import { ActionName } from '../types' import { NTQQGroupApi } from '../../../ntqqapi/api/group' +import { log } from '../../../common/utils' export interface PayloadType { - group_id: number + group_id: number, + no_cache: boolean | string } class GetGroupMemberList extends BaseAction { @@ -15,8 +17,9 @@ class GetGroupMemberList extends BaseAction { protected async _handle(payload: PayloadType) { const group = await getGroup(payload.group_id.toString()) if (group) { - if (!group.members?.length) { + if (!group.members?.length || payload.no_cache === true || payload.no_cache === 'true') { group.members = await NTQQGroupApi.getGroupMembers(payload.group_id.toString()) + log('强制刷新群成员列表, 数量: ', group.members.length) } return OB11Constructor.groupMembers(group) } else { diff --git a/src/onebot11/action/msg/DeleteMsg.ts b/src/onebot11/action/msg/DeleteMsg.ts index c85d6d5..d1bc1c8 100644 --- a/src/onebot11/action/msg/DeleteMsg.ts +++ b/src/onebot11/action/msg/DeleteMsg.ts @@ -12,6 +12,9 @@ class DeleteMsg extends BaseAction { protected async _handle(payload: Payload) { let msg = await dbUtil.getMsgByShortId(payload.message_id) + if (!msg) { + throw `消息${payload.message_id}不存在` + } await NTQQMsgApi.recallMsg( { chatType: msg.chatType, diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 305474c..ad21e79 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -179,7 +179,7 @@ export async function createSendElements( break case OB11MessageDataType.mface: { sendElements.push( - SendMsgElementConstructor.mface(sendMsg.data.emoji_package_id, sendMsg.data.emoji_id, sendMsg.data.key, sendMsg.data.summary || ""), + SendMsgElementConstructor.mface(sendMsg.data.emoji_package_id, sendMsg.data.emoji_id, sendMsg.data.key, sendMsg.data.summary), ) } case OB11MessageDataType.image: diff --git a/src/onebot11/action/user/GetFriendList.ts b/src/onebot11/action/user/GetFriendList.ts index 19b0b9c..00ee660 100644 --- a/src/onebot11/action/user/GetFriendList.ts +++ b/src/onebot11/action/user/GetFriendList.ts @@ -3,11 +3,25 @@ import { OB11Constructor } from '../../constructor' import { friends } from '../../../common/data' import BaseAction from '../BaseAction' import { ActionName } from '../types' +import { NTQQFriendApi } from '../../../ntqqapi/api' +import { log } from '../../../common/utils' -class GetFriendList extends BaseAction { +interface Payload{ + no_cache: boolean | string +} + +class GetFriendList extends BaseAction { actionName = ActionName.GetFriendList - protected async _handle(payload: null) { + protected async _handle(payload: Payload) { + if (friends.length === 0 || payload?.no_cache === true || payload?.no_cache === 'true') { + const _friends = await NTQQFriendApi.getFriends(true) + // log('强制刷新好友列表,结果: ', _friends) + if (_friends.length > 0) { + friends.length = 0 + friends.push(..._friends) + } + } return OB11Constructor.friends(friends) } } diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts index 36acc8a..5d43688 100644 --- a/src/onebot11/constructor.ts +++ b/src/onebot11/constructor.ts @@ -44,6 +44,8 @@ import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent' import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent' import { NTQQGroupApi } from '../ntqqapi/api' import { OB11GroupMsgEmojiLikeEvent } from './event/notice/OB11MsgEmojiLikeEvent' +import { mFaceCache } from '../ntqqapi/constructor' +import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent' let lastRKeyUpdateTime = 0 @@ -247,6 +249,7 @@ export class OB11Constructor { message_data['data']['emoji_id'] = element.marketFaceElement.emojiId message_data['data']['emoji_package_id'] = String(element.marketFaceElement.emojiPackageId) message_data['data']['key'] = element.marketFaceElement.key + mFaceCache.set(md5, element.marketFaceElement.faceName); } else if (element.markdownElement) { message_data['type'] = OB11MessageDataType.markdown message_data['data']['data'] = element.markdownElement.content @@ -458,6 +461,16 @@ export class OB11Constructor { } } + static async FriendAddEvent(msg: RawMessage): Promise { + if (msg.chatType !== ChatType.friend) { + return; + } + if (msg.msgType === 5 && msg.subMsgType === 12) { + const event = new OB11FriendAddNoticeEvent(parseInt(msg.peerUin)); + return event; + } + return; + } static friend(friend: User): OB11User { return { user_id: parseInt(friend.uin), diff --git a/src/onebot11/event/notice/OB11FriendAddNoticeEvent.ts b/src/onebot11/event/notice/OB11FriendAddNoticeEvent.ts new file mode 100644 index 0000000..25ea23a --- /dev/null +++ b/src/onebot11/event/notice/OB11FriendAddNoticeEvent.ts @@ -0,0 +1,11 @@ +import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; + +export class OB11FriendAddNoticeEvent extends OB11BaseNoticeEvent { + notice_type = 'friend_add'; + user_id: number; + + public constructor(userId: number) { + super(); + this.user_id = userId; + } +} diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 4dc969f..bee2b41 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -165,12 +165,12 @@ async function onSettingWindowCreated(view: Element) { }`, SettingButton('选择ffmpeg', 'config-ffmpeg-select'), ), - // SettingItem( - // '音乐卡片签名地址', - // null, - // `
`, - // 'config-musicSignUrl', - // ), + SettingItem( + '音乐卡片签名地址', + null, + `
`, + 'config-musicSignUrl', + ), SettingItem('', null, SettingButton('保存', 'config-ob11-save', 'primary')), ]), SettingList([ diff --git a/src/version.ts b/src/version.ts index 9d5ae7c..68f0fe0 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '3.23.0' +export const version = '3.24.0'