Compare commits

...

8 Commits

Author SHA1 Message Date
Alen
71ae08706b release: v2.0.35 2024-08-20 16:49:16 +08:00
Alen
50dd798757 Merge pull request #285 from cnxysoft/upmain
refactor: 接口兼容
2024-08-20 16:39:51 +08:00
Alen
0c8cf73746 refactor: 接口兼容
调整SetGroupHeader接口为SetGroupPortrait,使其兼容gocq标准
2024-08-20 16:35:23 +08:00
Alen
1bee811312 refactor: 接口兼容
调整SetSelfProfile接口为SetQQProfile,使其兼容gocq标准
2024-08-20 16:05:23 +08:00
Alen
b4c0068637 Merge pull request #284 from cnxysoft/upmain
fix: 多处修复
2024-08-20 14:31:02 +08:00
Alen
f484c6e5fe fix: 多处修复
1.修复group_card事件上报
2.修复group_admin事件上报
2024-08-20 14:28:32 +08:00
Alen
7a08187c5f fix: Uid转Uin
修复Uid转Uin兜底逻辑
2024-08-20 07:28:25 +08:00
Alen
c4d7d5a0d4 fix: 多处修改
1.修改(疑似)旧设备回复消息验证失败的解决方案
2.修复Base64发送文件失败
3.修复群时间监听器未注册
2024-08-20 01:02:03 +08:00
15 changed files with 110 additions and 76 deletions

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ", "name": "NapCatQQ",
"slug": "NapCat.Framework", "slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现", "description": "高性能的 OneBot 11 协议实现",
"version": "2.0.34", "version": "2.0.35",
"icon": "./logo.png", "icon": "./logo.png",
"authors": [ "authors": [
{ {

View File

@@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "2.0.34", "version": "2.0.35",
"scripts": { "scripts": {
"build:framework": "vite build --mode framework", "build:framework": "vite build --mode framework",
"build:shell": "vite build --mode shell", "build:shell": "vite build --mode shell",

View File

@@ -2,7 +2,7 @@ import path, { dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import fs from 'fs'; import fs from 'fs';
export const napcat_version = '2.0.34'; export const napcat_version = '2.0.35';
export class NapCatPathWrapper { export class NapCatPathWrapper {
binaryPath: string; binaryPath: string;

View File

@@ -127,13 +127,16 @@ export class NTQQUserApi {
return RetUser; return RetUser;
} }
async getUserDetailInfo(uid: string) { async getUserDetailInfo(uid: string): Promise<User> {
const ret = await this.fetchUserDetailInfo(uid, UserDetailSource.KDB); try {
if (ret.uin === '0') { let retUser = await this.fetchUserDetailInfo(uid, UserDetailSource.KDB);
this.context.logger.logDebug('[NapCat] [Mark] getUserDetailInfo Mode1 Failed.') if (retUser.uin !== '0') {
return await this.fetchUserDetailInfo(uid, UserDetailSource.KSERVER); return retUser;
}
} catch (e) {
} }
return ret; this.context.logger.logDebug('[NapCat] [Mark] getUserDetailInfo Mode1 Failed.');
return this.fetchUserDetailInfo(uid, UserDetailSource.KSERVER);
} }
async modifySelfProfile(param: ModifyProfileParams) { async modifySelfProfile(param: ModifyProfileParams) {

View File

@@ -196,6 +196,9 @@ export class NapCatCore {
this.apis.GroupApi.groupMemberCache.set(groupCode, members); this.apis.GroupApi.groupMemberCache.set(groupCode, members);
} }
}; };
this.context.session.getGroupService().addKernelGroupListener(
new this.context.wrapper.NodeIKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger)),
);
} }
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean { checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean {
if (memberNew.role !== memberOld?.role) { if (memberNew.role !== memberOld?.role) {

View File

@@ -1,32 +0,0 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
nick: { type: 'string' },
longNick: { type: 'string' },
sex: { type: ['number', 'string'] },//传Sex值建议传0
},
required: ['nick', 'longNick', 'sex'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class SetSelfProfile extends BaseAction<Payload, any | null> {
actionName = ActionName.SetSelfProfile;
PayloadSchema = SchemaData;
async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi;
const ret = await NTQQUserApi.modifySelfProfile({
nick: payload.nick,
longNick: payload.longNick,
sex: parseInt(payload.sex.toString()),
birthday: { birthday_year: '', birthday_month: '', birthday_day: '' },
location: undefined,
});
return ret;
}
}

View File

@@ -7,18 +7,18 @@ import { checkFileReceived, uri2local } from '@/common/utils/file';
interface Payload { interface Payload {
file: string, file: string,
groupCode: string group_id: number
} }
export default class SetGroupHeader extends BaseAction<Payload, any> { export default class SetGroupPortrait extends BaseAction<Payload, any> {
actionName = ActionName.SetGroupHeader; actionName = ActionName.SetGroupPortrait;
// 用不着复杂检测 // 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> { protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string' || !payload.groupCode || typeof payload.groupCode != 'string') { if (!payload.file || typeof payload.file != 'string' || !payload.group_id || typeof payload.group_id != 'number') {
return { return {
valid: false, valid: false,
message: 'file和groupCode字段不能为空或者类型错误', message: 'file和group_id字段不能为空或者类型错误',
}; };
} }
return { return {
@@ -34,7 +34,7 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
} }
if (path) { if (path) {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断 await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQGroupApi.setGroupAvatar(payload.groupCode, path); const ret = await NTQQGroupApi.setGroupAvatar(payload.group_id.toString(), path) as any;
if (!isLocal) { if (!isLocal) {
fs.unlink(path, () => { fs.unlink(path, () => {
}); });
@@ -43,11 +43,11 @@ export default class SetGroupHeader extends BaseAction<Payload, any> {
throw `头像${payload.file}设置失败,api无返回`; throw `头像${payload.file}设置失败,api无返回`;
} }
// log(`头像设置返回:${JSON.stringify(ret)}`) // log(`头像设置返回:${JSON.stringify(ret)}`)
// if (ret['result'] == 1004022) { if (ret['result'] == 1004022) {
// throw `头像${payload.file}设置失败,文件可能不是图片格式`; throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`;
// } else if (ret['result'] != 0) { } else if (ret['result'] != 0) {
// throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`; throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
// } }
return ret; return ret;
} else { } else {
if (!isLocal) { if (!isLocal) {

View File

@@ -0,0 +1,34 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
nickname: { type: 'string' },
personal_note: { type: 'string' },
sex: { type: ['number', 'string'] },//传Sex值建议传0
},
required: ['nickname'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class SetQQProfile extends BaseAction<Payload, any | null> {
actionName = ActionName.SetQQProfile;
PayloadSchema = SchemaData;
async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi;
const self = this.CoreContext.selfInfo;
const OldProfile = await NTQQUserApi.getUserDetailInfo(self.uid);
const ret = await NTQQUserApi.modifySelfProfile({
nick: payload.nickname,
longNick: payload?.personal_note ?? OldProfile?.longNick!,
sex: parseInt(payload?.sex ? payload?.sex.toString() : OldProfile?.sex!.toString()),
birthday: { birthday_year: OldProfile?.birthday_year!.toString(), birthday_month: OldProfile?.birthday_month!.toString(), birthday_day: OldProfile?.birthday_day!.toString() },
location: undefined,
});
return ret;
}
}

View File

@@ -61,7 +61,7 @@ import { TranslateEnWordToZn } from './extends/TranslateEnWordToZn';
import { SetGroupFileFolder } from './file/SetGroupFileFolder'; import { SetGroupFileFolder } from './file/SetGroupFileFolder';
import { DelGroupFile } from './file/DelGroupFile'; import { DelGroupFile } from './file/DelGroupFile';
import { DelGroupFileFolder } from './file/DelGroupFileFolder'; import { DelGroupFileFolder } from './file/DelGroupFileFolder';
import { SetSelfProfile } from './extends/SetSelfProfile'; import { SetQQProfile } from './go-cqhttp/SetQQProfile'
import { ShareGroupEx, SharePeer } from './extends/ShareContact'; import { ShareGroupEx, SharePeer } from './extends/ShareContact';
import { CreateCollection } from './extends/CreateCollection'; import { CreateCollection } from './extends/CreateCollection';
import { SetLongNick } from './extends/SetLongNick'; import { SetLongNick } from './extends/SetLongNick';
@@ -69,7 +69,7 @@ import DelEssenceMsg from './group/DelEssenceMsg';
import SetEssenceMsg from './group/SetEssenceMsg'; import SetEssenceMsg from './group/SetEssenceMsg';
import GetRecentContact from './user/GetRecentContact'; import GetRecentContact from './user/GetRecentContact';
import { GetProfileLike } from './extends/GetProfileLike'; import { GetProfileLike } from './extends/GetProfileLike';
import SetGroupHeader from './extends/SetGroupHeader'; import SetGroupPortrait from './go-cqhttp/SetGroupPortrait';
import { FetchCustomFace } from './extends/FetchCustomFace'; import { FetchCustomFace } from './extends/FetchCustomFace';
import GoCQHTTPUploadPrivateFile from './go-cqhttp/UploadPrivareFile'; import GoCQHTTPUploadPrivateFile from './go-cqhttp/UploadPrivareFile';
import { FetchEmojiLike } from './extends/FetchEmojiLike'; import { FetchEmojiLike } from './extends/FetchEmojiLike';
@@ -86,7 +86,7 @@ export function createActionMap(onebotContext: NapCatOneBot11Adapter, coreContex
const actionHandlers = [ const actionHandlers = [
new FetchEmojiLike(onebotContext, coreContext), new FetchEmojiLike(onebotContext, coreContext),
new GetFile(onebotContext, coreContext), new GetFile(onebotContext, coreContext),
new SetSelfProfile(onebotContext, coreContext), new SetQQProfile(onebotContext, coreContext),
new ShareGroupEx(onebotContext, coreContext), new ShareGroupEx(onebotContext, coreContext),
new SharePeer(onebotContext, coreContext), new SharePeer(onebotContext, coreContext),
new CreateCollection(onebotContext, coreContext), new CreateCollection(onebotContext, coreContext),
@@ -161,7 +161,7 @@ export function createActionMap(onebotContext: NapCatOneBot11Adapter, coreContex
new GetRecentContact(onebotContext, coreContext), new GetRecentContact(onebotContext, coreContext),
new MarkAllMsgAsRead(onebotContext, coreContext), new MarkAllMsgAsRead(onebotContext, coreContext),
new GetProfileLike(onebotContext, coreContext), new GetProfileLike(onebotContext, coreContext),
new SetGroupHeader(onebotContext, coreContext), new SetGroupPortrait(onebotContext, coreContext),
new FetchCustomFace(onebotContext, coreContext), new FetchCustomFace(onebotContext, coreContext),
new GoCQHTTPUploadPrivateFile(onebotContext, coreContext), new GoCQHTTPUploadPrivateFile(onebotContext, coreContext),
new GetGuildProfile(onebotContext, coreContext), new GetGuildProfile(onebotContext, coreContext),

View File

@@ -56,7 +56,7 @@ const _handlers: {
if (atQQ === 'all') return SendMsgElementConstructor.at(coreContext, atQQ, atQQ, AtType.atAll, '全体成员'); if (atQQ === 'all') return SendMsgElementConstructor.at(coreContext, atQQ, atQQ, AtType.atAll, '全体成员');
// then the qq is a group member // then the qq is a group member
// Mlikiowa V2.0.34 Refactor Todo // Mlikiowa V2.0.35 Refactor Todo
const uid = await coreContext.apis.UserApi.getUidByUinV2(`${atQQ}`); const uid = await coreContext.apis.UserApi.getUidByUinV2(`${atQQ}`);
if (!uid) throw new Error('Get Uid Error'); if (!uid) throw new Error('Get Uid Error');
return SendMsgElementConstructor.at(coreContext, atQQ, uid, AtType.atUser, ''); return SendMsgElementConstructor.at(coreContext, atQQ, uid, AtType.atUser, '');
@@ -161,7 +161,7 @@ const _handlers: {
} else { } else {
postData = data; postData = data;
} }
// Mlikiowa V2.0.34 Refactor Todo // Mlikiowa V2.0.35 Refactor Todo
const signUrl = obContext.configLoader.configData.musicSignUrl; const signUrl = obContext.configLoader.configData.musicSignUrl;
if (!signUrl) { if (!signUrl) {
if (data.type === 'qq') { if (data.type === 'qq') {

View File

@@ -91,7 +91,7 @@ export enum ActionName {
GetOnlineClient = 'get_online_clients', GetOnlineClient = 'get_online_clients',
OCRImage = 'ocr_image', OCRImage = 'ocr_image',
IOCRImage = '.ocr_image', IOCRImage = '.ocr_image',
SetSelfProfile = 'set_self_profile', SetQQProfile = 'set_qq_profile',
CreateCollection = 'create_collection', CreateCollection = 'create_collection',
GetCollectionList = 'get_collection_list', GetCollectionList = 'get_collection_list',
SetLongNick = 'set_self_longnick', SetLongNick = 'set_self_longnick',
@@ -100,7 +100,7 @@ export enum ActionName {
GetRecentContact = 'get_recent_contact', GetRecentContact = 'get_recent_contact',
_MarkAllMsgAsRead = '_mark_all_as_read', _MarkAllMsgAsRead = '_mark_all_as_read',
GetProfileLike = 'get_profile_like', GetProfileLike = 'get_profile_like',
SetGroupHeader = 'set_group_head', SetGroupPortrait = 'set_group_portrait',
FetchCustomFace = 'fetch_custom_face', FetchCustomFace = 'fetch_custom_face',
GOCQHTTP_UploadPrivateFile = 'upload_private_file', GOCQHTTP_UploadPrivateFile = 'upload_private_file',
TestApi01 = 'test_api_01', TestApi01 = 'test_api_01',

View File

@@ -30,6 +30,7 @@ import { EventType } from '../event/OB11BaseEvent';
import { encodeCQCode } from './cqcode'; import { encodeCQCode } from './cqcode';
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent'; import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
import { OB11GroupBanEvent } from '../event/notice/OB11GroupBanEvent'; import { OB11GroupBanEvent } from '../event/notice/OB11GroupBanEvent';
import { OB11GroupCardEvent } from '../event/notice/OB11GroupCardEvent';
import { OB11GroupUploadNoticeEvent } from '../event/notice/OB11GroupUploadNoticeEvent'; import { OB11GroupUploadNoticeEvent } from '../event/notice/OB11GroupUploadNoticeEvent';
import { OB11GroupNoticeEvent } from '../event/notice/OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from '../event/notice/OB11GroupNoticeEvent';
import { calcQQLevel, sleep, UUIDConverter } from '@/common/utils/helper'; import { calcQQLevel, sleep, UUIDConverter } from '@/common/utils/helper';
@@ -149,7 +150,6 @@ export class OB11Constructor {
message_data['type'] = OB11MessageDataType.reply; message_data['type'] = OB11MessageDataType.reply;
//log("收到回复消息", element.replyElement); //log("收到回复消息", element.replyElement);
try { try {
let oldMsgFlag = false;
const records = msg.records.find(msgRecord => msgRecord.msgId === element?.replyElement?.sourceMsgIdInRecords); const records = msg.records.find(msgRecord => msgRecord.msgId === element?.replyElement?.sourceMsgIdInRecords);
const peer = { const peer = {
chatType: msg.chatType, chatType: msg.chatType,
@@ -164,14 +164,17 @@ export class OB11Constructor {
chatType: msg.chatType, chatType: msg.chatType,
}, element.replyElement.replayMsgSeq, 1, true, true)).msgList.find(msg => msg.msgRandom === records.msgRandom); }, element.replyElement.replayMsgSeq, 1, true, true)).msgList.find(msg => msg.msgRandom === records.msgRandom);
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) { if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
if (!replyMsg && records.msgRandom === '0') oldMsgFlag = true;
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0]; replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0];
} }
if (msg.peerUin == '284840486') { if (msg.peerUin == '284840486') {
//合并消息内侧 消息具体定位不到 //合并消息内侧 消息具体定位不到
} }
if ((!replyMsg || (records.msgRandom !== replyMsg.msgRandom && !oldMsgFlag || (oldMsgFlag && records.msgSeq !== replyMsg.msgSeq))) && msg.peerUin !== '284840486') { if ((!replyMsg || records.msgRandom !== replyMsg.msgRandom) && msg.peerUin !== '284840486') {
throw new Error('回复消息消息验证失败'); const replyMsgList = (await NTQQMsgApi.getMsgExBySeq(peer, records.msgSeq)).msgList;
if (replyMsgList.length < 1) {
throw new Error('回复消息消息验证失败');
}
replyMsg = replyMsgList.filter(e => e.msgSeq == records.msgSeq).sort((a, b) => parseInt(a.msgTime) - parseInt(b.msgTime))[0];
} }
message_data['data']['id'] = MessageUnique.createMsg({ message_data['data']['id'] = MessageUnique.createMsg({
peerUid: msg.peerUid, peerUid: msg.peerUid,
@@ -419,16 +422,15 @@ export class OB11Constructor {
return; return;
} }
//log("group msg", msg); //log("group msg", msg);
// Mlikiowa V2.0.34 Refactor Todo if (msg.senderUin && msg.senderUin !== '0') {
// if (msg.senderUin && msg.senderUin !== '0') { const member = await NTQQGroupApi.getGroupMember(msg.peerUid, msg.senderUin);
// const member = await getGroupMember(msg.peerUid, msg.senderUin); if (member && member.cardName !== msg.sendMemberName) {
// if (member && member.cardName !== msg.sendMemberName) { const newCardName = msg.sendMemberName || '';
// const newCardName = msg.sendMemberName || ''; const event = new OB11GroupCardEvent(core, parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName);
// const event = new OB11GroupCardEvent(parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName); member.cardName = newCardName;
// member.cardName = newCardName; return event;
// return event; }
// } }
// }
for (const element of msg.elements) { for (const element of msg.elements) {
const grayTipElement = element.grayTipElement; const grayTipElement = element.grayTipElement;

View File

@@ -9,6 +9,7 @@ import {
NapCatCore, NapCatCore,
RawMessage, RawMessage,
SendStatusType, SendStatusType,
GroupMemberRole,
} from '@/core'; } from '@/core';
import { OB11Config, OB11ConfigLoader } from '@/onebot/helper/config'; import { OB11Config, OB11ConfigLoader } from '@/onebot/helper/config';
import { OneBotApiContextType } from '@/onebot/types'; import { OneBotApiContextType } from '@/onebot/types';
@@ -413,6 +414,29 @@ export class NapCatOneBot11Adapter {
} }
}; };
groupListener.onMemberInfoChange = async (groupCode, changeType, members) => {
//this.context.logger.logDebug('收到群成员信息变动通知', groupCode, changeType);
if (changeType === 0) {
const existMembers = this.core.apis.GroupApi.groupMemberCache.get(groupCode);
if (!existMembers) return;
members.forEach((member) => {
const existMember = existMembers.get(member.uid);
if (!existMember?.isChangeRole) return;
this.context.logger.logDebug('变动管理员获取成功');
const groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent(
this.core,
parseInt(groupCode),
parseInt(member.uin),
member.role === GroupMemberRole.admin ? 'set' : 'unset',
);
this.networkManager.emitEvent(groupAdminNoticeEvent)
.catch(e => this.context.logger.logError('处理群管理员变动失败', e));
existMember.isChangeRole = false;
this.context.logger.logDebug('群管理员变动处理完毕');
});
}
};
this.context.session.getGroupService().addKernelGroupListener( this.context.session.getGroupService().addKernelGroupListener(
new this.context.wrapper.NodeIKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger)), new this.context.wrapper.NodeIKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger)),
); );

View File

@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem( SettingItem(
'<span id="napcat-update-title">Napcat</span>', '<span id="napcat-update-title">Napcat</span>',
undefined, undefined,
SettingButton('V2.0.34', 'napcat-update-button', 'secondary'), SettingButton('V2.0.35', 'napcat-update-button', 'secondary'),
), ),
]), ]),
SettingList([ SettingList([

View File

@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
SettingItem( SettingItem(
'<span id="napcat-update-title">Napcat</span>', '<span id="napcat-update-title">Napcat</span>',
void 0, void 0,
SettingButton("V2.0.34", "napcat-update-button", "secondary") SettingButton("V2.0.35", "napcat-update-button", "secondary")
) )
]), ]),
SettingList([ SettingList([