mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1070278eaf | ||
![]() |
16b1a6b153 | ||
![]() |
096a7534e0 | ||
![]() |
b0897187d2 | ||
![]() |
885d94882d | ||
![]() |
11a3341e13 | ||
![]() |
231890f78a |
@@ -1,12 +0,0 @@
|
|||||||
# v1.7.8
|
|
||||||
|
|
||||||
QQ Version: Windows 9.9.15-26702 / Linux 3.2.12-26702
|
|
||||||
|
|
||||||
## 启动的方式
|
|
||||||
Way03/Way05
|
|
||||||
|
|
||||||
## 新增与调整
|
|
||||||
1. 彻底支持发言时间与入群时间 For 26702
|
|
||||||
2. 修复转发接口异常问题
|
|
||||||
|
|
||||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
|
21
docs/changelogs/CHANGELOG.v1.7.9.md
Normal file
21
docs/changelogs/CHANGELOG.v1.7.9.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# v1.8.0
|
||||||
|
|
||||||
|
QQ Version: Windows 9.9.15-26702 / Linux 3.2.12-26702
|
||||||
|
|
||||||
|
## 启动的方式
|
||||||
|
Way03/Way05
|
||||||
|
|
||||||
|
## 新增与调整
|
||||||
|
1. 消息ID映射到UINT32空间
|
||||||
|
2. 回复ID验证与修复
|
||||||
|
3. 新API /fetch_emoji_like
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"message_id": 1557274996,//消息ID
|
||||||
|
"emojiType": "1",//可以从event事件获取 一般为1或者2
|
||||||
|
"emojiId": "76"//可以从event事件获取 一个表情对应一个ID
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.7.8",
|
"version": "1.8.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch:dev": "vite --mode development",
|
"watch:dev": "vite --mode development",
|
||||||
"watch:prod": "vite --mode production",
|
"watch:prod": "vite --mode production",
|
||||||
|
@@ -99,8 +99,10 @@ class MessageUniqueWrapper {
|
|||||||
}
|
}
|
||||||
createMsg(peer: Peer, msgId: string): number | undefined {
|
createMsg(peer: Peer, msgId: string): number | undefined {
|
||||||
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
|
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
|
||||||
const hash = crypto.createHash('md5').update(key);
|
const hash = crypto.createHash('md5').update(key).digest();
|
||||||
const shortId = hash.digest().readInt32BE(0);
|
//设置第一个bit为0 保证shortId为正数
|
||||||
|
hash[0] &= 0x7f;
|
||||||
|
const shortId = hash.readInt32BE(0);
|
||||||
//减少性能损耗
|
//减少性能损耗
|
||||||
// const isExist = this.msgIdMap.getKey(shortId);
|
// const isExist = this.msgIdMap.getKey(shortId);
|
||||||
// if (isExist && isExist === msgId) {
|
// if (isExist && isExist === msgId) {
|
||||||
|
@@ -67,6 +67,10 @@ setTimeout(() => {
|
|||||||
// }, 25000)
|
// }, 25000)
|
||||||
|
|
||||||
export class NTQQMsgApi {
|
export class NTQQMsgApi {
|
||||||
|
static async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
|
||||||
|
//console.log(peer, msgSeq, emojiId, emojiType, count);
|
||||||
|
return napCatCore.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, "", false, 20)
|
||||||
|
}
|
||||||
// static napCatCore: NapCatCore | null = null;
|
// static napCatCore: NapCatCore | null = null;
|
||||||
// enum BaseEmojiType {
|
// enum BaseEmojiType {
|
||||||
// NORMAL_EMOJI,
|
// NORMAL_EMOJI,
|
||||||
|
@@ -477,7 +477,19 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
setMsgEmojiLikes(...args: unknown[]): unknown;
|
setMsgEmojiLikes(...args: unknown[]): unknown;
|
||||||
|
|
||||||
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<unknown>;
|
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<{
|
||||||
|
result: number,
|
||||||
|
errMsg: string,
|
||||||
|
emojiLikesList:
|
||||||
|
Array<{
|
||||||
|
tinyId: string,
|
||||||
|
nickName: string,
|
||||||
|
headUrl: string
|
||||||
|
}>,
|
||||||
|
cookie: string,
|
||||||
|
isLastPage: boolean,
|
||||||
|
isFirstPage: boolean
|
||||||
|
}>;
|
||||||
|
|
||||||
setMsgEmojiLikesForRole(...args: unknown[]): unknown;
|
setMsgEmojiLikesForRole(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -592,7 +604,7 @@ export interface NodeIKernelMsgService {
|
|||||||
// this.selfPhone = str5;
|
// this.selfPhone = str5;
|
||||||
// this.gameSession = tempChatGameSession;
|
// this.gameSession = tempChatGameSession;
|
||||||
prepareTempChat(args: unknown): unknown;//主动临时消息 不做
|
prepareTempChat(args: unknown): unknown;//主动临时消息 不做
|
||||||
|
|
||||||
sendSsoCmdReqByContend(cmd: string, param: string): Promise<unknown>;
|
sendSsoCmdReqByContend(cmd: string, param: string): Promise<unknown>;
|
||||||
|
|
||||||
//chattype,uid->Promise<any>
|
//chattype,uid->Promise<any>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Peer } from "../entities";
|
import { ChatType, Peer } from "../entities";
|
||||||
import { NodeIKernelRecentContactListener } from "../listeners/NodeIKernelRecentContactListener";
|
import { NodeIKernelRecentContactListener } from "../listeners/NodeIKernelRecentContactListener";
|
||||||
import { GeneralCallResult } from "./common";
|
import { GeneralCallResult } from "./common";
|
||||||
export interface FSABRecentContactParams {
|
export interface FSABRecentContactParams {
|
||||||
@@ -39,7 +39,13 @@ export interface NodeIKernelRecentContactService {
|
|||||||
errCode: number,
|
errCode: number,
|
||||||
errMsg: string,
|
errMsg: string,
|
||||||
sortedContactList: Array<number>,
|
sortedContactList: Array<number>,
|
||||||
changedList: Array<any>
|
changedList: Array<{
|
||||||
|
remark: any;
|
||||||
|
peerName: any;
|
||||||
|
sendMemberName: any;
|
||||||
|
sendNickName: any;
|
||||||
|
peerUid: string; peerUin: string, msgTime: string, chatType: ChatType, msgId: string
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
}>; // 1 arguments
|
}>; // 1 arguments
|
||||||
|
|
||||||
|
32
src/onebot11/action/extends/FetchEmojioLike.ts
Normal file
32
src/onebot11/action/extends/FetchEmojioLike.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//getMsgEmojiLikesList
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { NTQQMsgApi } from '@/core/apis';
|
||||||
|
import { MessageUnique } from '@/common/utils/MessageUnique';
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
user_id: { type: 'string' },
|
||||||
|
group_id: { type: 'string' },
|
||||||
|
emojiId: { type: 'string' },
|
||||||
|
emojiType: { type: 'string' },
|
||||||
|
message_id: { type: ['string', 'number'] },
|
||||||
|
count: { type: 'number' }
|
||||||
|
},
|
||||||
|
required: ['emojiId', 'emojiType', 'message_id']
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class FetchEmojioLike extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.FetchEmojioLike;
|
||||||
|
PayloadSchema = SchemaData;
|
||||||
|
protected async _handle(payload: Payload) {
|
||||||
|
let msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
|
||||||
|
if(!msgIdPeer) throw new Error('消息不存在');
|
||||||
|
let msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
|
||||||
|
const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer,msg.msgSeq,payload.emojiId,payload.emojiType,payload.count);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
@@ -78,8 +78,10 @@ import SetGroupHeader from './extends/SetGroupHeader';
|
|||||||
import { FetchCustomFace } from './extends/FetchCustomFace';
|
import { FetchCustomFace } from './extends/FetchCustomFace';
|
||||||
import GoCQHTTPUploadPrivateFile from './go-cqhttp/UploadPrivareFile';
|
import GoCQHTTPUploadPrivateFile from './go-cqhttp/UploadPrivareFile';
|
||||||
import TestApi01 from './extends/TestApi01';
|
import TestApi01 from './extends/TestApi01';
|
||||||
|
import { FetchEmojioLike } from './extends/FetchEmojioLike';
|
||||||
|
|
||||||
export const actionHandlers = [
|
export const actionHandlers = [
|
||||||
|
new FetchEmojioLike(),
|
||||||
new RebootNormal(),
|
new RebootNormal(),
|
||||||
new GetFile(),
|
new GetFile(),
|
||||||
new Debug(),
|
new Debug(),
|
||||||
|
@@ -102,5 +102,6 @@ export enum ActionName {
|
|||||||
SetGroupHeader = 'set_group_head',
|
SetGroupHeader = 'set_group_head',
|
||||||
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',
|
||||||
|
FetchEmojioLike = "fetch_emoji_like"
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,52 @@
|
|||||||
|
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { NTQQUserApi } from '@/core';
|
import { NTQQMsgApi, NTQQUserApi } from '@/core';
|
||||||
|
import { OB11Constructor } from '@/onebot11/constructor';
|
||||||
|
|
||||||
export default class GetRecentContact extends BaseAction<void, any> {
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
count: { type: ['number', 'string'] }
|
||||||
|
}
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export default class GetRecentContact extends BaseAction<Payload, any> {
|
||||||
actionName = ActionName.GetRecentContact;
|
actionName = ActionName.GetRecentContact;
|
||||||
protected async _handle(payload: void) {
|
PayloadSchema = SchemaData;
|
||||||
//没有效果
|
protected async _handle(payload: Payload) {
|
||||||
return await NTQQUserApi.getRecentContactListSnapShot(10);
|
let ret = await NTQQUserApi.getRecentContactListSnapShot(parseInt((payload.count || 10).toString()));
|
||||||
|
let data = await Promise.all(ret.info.changedList.map(async (t) => {
|
||||||
|
let FastMsg = await NTQQMsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]);
|
||||||
|
if (FastMsg.msgList.length > 0) {
|
||||||
|
//扩展ret.info.changedList
|
||||||
|
let lastestMsg = await OB11Constructor.message(FastMsg.msgList[0]);
|
||||||
|
return {
|
||||||
|
lastestMsg: lastestMsg,
|
||||||
|
peerUin: t.peerUin,
|
||||||
|
remark: t.remark,
|
||||||
|
msgTime: t.msgTime,
|
||||||
|
chatType: t.chatType,
|
||||||
|
msgId: t.msgId,
|
||||||
|
sendNickName: t.sendNickName,
|
||||||
|
sendMemberName: t.sendMemberName,
|
||||||
|
peerName: t.peerName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
peerUin: t.peerUin,
|
||||||
|
remark: t.remark,
|
||||||
|
msgTime: t.msgTime,
|
||||||
|
chatType: t.chatType,
|
||||||
|
msgId: t.msgId,
|
||||||
|
sendNickName: t.sendNickName,
|
||||||
|
sendMemberName: t.sendMemberName,
|
||||||
|
peerName: t.peerName
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -153,21 +153,20 @@ export class OB11Constructor {
|
|||||||
message_data['type'] = OB11MessageDataType.reply;
|
message_data['type'] = OB11MessageDataType.reply;
|
||||||
//log("收到回复消息", element.replyElement);
|
//log("收到回复消息", element.replyElement);
|
||||||
try {
|
try {
|
||||||
//做这么多都是因为NC速度太快 可能nt还没有写入数据库
|
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,
|
||||||
peerUid: msg.peerUid,
|
peerUid: msg.peerUid,
|
||||||
guildId: '',
|
guildId: '',
|
||||||
};
|
};
|
||||||
let replyMsg: RawMessage | undefined;
|
let replyMsg: RawMessage | undefined;
|
||||||
|
if (!records) throw new Error('找不到回复消息');
|
||||||
replyMsg = (await NTQQMsgApi.getMsgsBySeqAndCount({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, element.replyElement.replayMsgSeq, 1, true, true)).msgList[0];
|
replyMsg = (await NTQQMsgApi.getMsgsBySeqAndCount({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, element.replyElement.replayMsgSeq, 1, true, true)).msgList[0];
|
||||||
if (!replyMsg || element.replyElement.replayMsgSeq !== replyMsg.msgSeq) {
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0];
|
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!replyMsg || element.replyElement.replayMsgSeq !== replyMsg.msgSeq) {
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
throw new Error('回复消息消息验证失败');
|
throw new Error('回复消息消息验证失败');
|
||||||
}
|
}
|
||||||
message_data['data']['id'] = MessageUnique.createMsg({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, replyMsg.msgId)?.toString();
|
message_data['data']['id'] = MessageUnique.createMsg({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, replyMsg.msgId)?.toString();
|
||||||
@@ -459,6 +458,7 @@ export class OB11Constructor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (grayTipElement) {
|
if (grayTipElement) {
|
||||||
|
//console.log('收到群提示消息', grayTipElement);
|
||||||
if (grayTipElement.xmlElement?.templId === '10382') {
|
if (grayTipElement.xmlElement?.templId === '10382') {
|
||||||
const emojiLikeData = new fastXmlParser.XMLParser({
|
const emojiLikeData = new fastXmlParser.XMLParser({
|
||||||
ignoreAttributes: false,
|
ignoreAttributes: false,
|
||||||
|
@@ -98,6 +98,8 @@ export class NapCatOnebot11 {
|
|||||||
// .map(x => x.toString(16).padStart(2, '0'))
|
// .map(x => x.toString(16).padStart(2, '0'))
|
||||||
// .join('');
|
// .join('');
|
||||||
// }
|
// }
|
||||||
|
// const hex = buf2hex(Buffer.from(protobufData));
|
||||||
|
// console.log(hex);
|
||||||
// // let Data: Data = {
|
// // let Data: Data = {
|
||||||
// // header: {
|
// // header: {
|
||||||
// // GroupNumber: 0,
|
// // GroupNumber: 0,
|
||||||
@@ -192,6 +194,7 @@ export class NapCatOnebot11 {
|
|||||||
// // 732 17 GroupRecall
|
// // 732 17 GroupRecall
|
||||||
// // 732 20 GroupCommonTips
|
// // 732 20 GroupCommonTips
|
||||||
// // 732 21 EssenceMessage
|
// // 732 21 EssenceMessage
|
||||||
|
// // 732 16 16 GrayTips ->Busi->GroupEmjioLike
|
||||||
// } catch (e) {
|
// } catch (e) {
|
||||||
// log('解析SysMsg异常', e);
|
// log('解析SysMsg异常', e);
|
||||||
// // console.log(e);
|
// // console.log(e);
|
||||||
@@ -209,7 +212,7 @@ export class NapCatOnebot11 {
|
|||||||
// 临时会话更新 tempGroupCodeMap uid -> source/GroupCode
|
// 临时会话更新 tempGroupCodeMap uid -> source/GroupCode
|
||||||
};
|
};
|
||||||
msgListener.onRecvMsg = async (msg) => {
|
msgListener.onRecvMsg = async (msg) => {
|
||||||
|
|
||||||
//console.log('ob11 onRecvMsg', JSON.stringify(msg, null, 2));
|
//console.log('ob11 onRecvMsg', JSON.stringify(msg, null, 2));
|
||||||
// logDebug('收到消息', msg);
|
// logDebug('收到消息', msg);
|
||||||
for (const m of msg) {
|
for (const m of msg) {
|
||||||
@@ -291,7 +294,7 @@ export class NapCatOnebot11 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
groupListener.onMemberInfoChange = async (groupCode: string, changeType: number, members: Map<string, GroupMember>) => {
|
groupListener.onMemberInfoChange = async (groupCode: string, changeType: number, members: Map<string, GroupMember>) => {
|
||||||
// console.log("ob11 onMemberInfoChange", groupCode, changeType, members)
|
// console.log("ob11 onMemberInfoChange", groupCode, changeType, members)
|
||||||
if (changeType === 1) {
|
if (changeType === 1) {
|
||||||
let member;
|
let member;
|
||||||
for (const [key, value] of members) {
|
for (const [key, value] of members) {
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const version = '1.7.8';
|
export const version = '1.8.0';
|
||||||
|
@@ -29,7 +29,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('V1.7.8', 'napcat-update-button', 'secondary')
|
SettingButton('V1.8.0', 'napcat-update-button', 'secondary')
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
@@ -163,7 +163,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("V1.7.8", "napcat-update-button", "secondary")
|
SettingButton("V1.8.0", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
Reference in New Issue
Block a user