mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
264cb6bbd2 | ||
![]() |
b7772e867b | ||
![]() |
cc0e77abfb | ||
![]() |
537d1c6f4f | ||
![]() |
80facadd67 | ||
![]() |
ba097dad23 | ||
![]() |
c13c15d046 | ||
![]() |
4f52128a06 | ||
![]() |
500b2d0e6d | ||
![]() |
e59d094feb | ||
![]() |
a8372f14f8 | ||
![]() |
5174ff422d | ||
![]() |
5c06751c3b |
@@ -28,10 +28,12 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||
|
||||
## 猫猫朋友
|
||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供初始版本基础
|
||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供部分参考
|
||||
|
||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
|
||||
|
||||
不过最最重要的 还是需要感谢屏幕前的你哦~
|
||||
|
||||
---
|
||||
|
||||
## 约法三章
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "2.3.5",
|
||||
"version": "2.3.7",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.3.5",
|
||||
"version": "2.3.7",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
|
@@ -167,7 +167,8 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
function msgElementToText(element: MessageElement) {
|
||||
if (element.textElement) {
|
||||
if (element.textElement.atType === AtType.notAt) {
|
||||
return element.textElement.content;
|
||||
const originalContentLines = element.textElement.content.split('\n');
|
||||
return `${originalContentLines[0]}${originalContentLines.length > 1 ? ' ...' : ''}`;
|
||||
} else if (element.textElement.atType === AtType.atAll) {
|
||||
return `@全体成员`;
|
||||
} else if (element.textElement.atType === AtType.atUser) {
|
||||
@@ -189,7 +190,7 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
}
|
||||
|
||||
if (element.picElement) {
|
||||
return `[图片 ${element.picElement.fileName}]`;
|
||||
return '[图片]';
|
||||
}
|
||||
|
||||
if (element.fileElement) {
|
||||
@@ -197,7 +198,7 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
}
|
||||
|
||||
if (element.videoElement) {
|
||||
return `[视频 ${element.videoElement.fileName}]`;
|
||||
return '[视频]';
|
||||
}
|
||||
|
||||
if (element.pttElement) {
|
||||
@@ -205,7 +206,7 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
}
|
||||
|
||||
if (element.arkElement) {
|
||||
return `[卡片消息 ${element.arkElement.bytesData}]`;
|
||||
return '[卡片消息]';
|
||||
}
|
||||
|
||||
if (element.faceElement) {
|
||||
@@ -213,19 +214,19 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
}
|
||||
|
||||
if (element.marketFaceElement) {
|
||||
return `[商城表情 ${element.marketFaceElement.faceName}]`;
|
||||
return element.marketFaceElement.faceName;
|
||||
}
|
||||
|
||||
if (element.markdownElement) {
|
||||
return `[Markdown ${element.markdownElement.content}]`;
|
||||
return '[Markdown 消息]';
|
||||
}
|
||||
|
||||
if (element.multiForwardMsgElement) {
|
||||
return `[转发消息]`;
|
||||
return '[转发消息]';
|
||||
}
|
||||
|
||||
if (element.elementType === ElementType.GreyTip) {
|
||||
return `[灰条消息]`; // TODO: resolve the text
|
||||
return '[灰条消息]';
|
||||
}
|
||||
|
||||
return `[未实现 (ElementType = ${element.elementType})]`;
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '2.3.5';
|
||||
export const napCatVersion = '2.3.7';
|
||||
|
@@ -9,8 +9,9 @@ import {
|
||||
MemberExtSourceType,
|
||||
NapCatCore,
|
||||
} from '@/core';
|
||||
import { isNumeric } from '@/common/helper';
|
||||
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
||||
import { LimitedHashTable } from '@/common/message-unique';
|
||||
import { NTEventWrapper } from '@/common/event';
|
||||
|
||||
export class NTQQGroupApi {
|
||||
context: InstanceContext;
|
||||
@@ -264,14 +265,34 @@ export class NTQQGroupApi {
|
||||
}
|
||||
return member;
|
||||
}
|
||||
|
||||
async getGroupMemberEx(GroupCode: string, uid: string, forced = false, retry = 2) {
|
||||
let data = await solveAsyncProblem((eventWrapper: NTEventWrapper, GroupCode: string, uid: string, forced = false) => {
|
||||
return eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelGroupService/getMemberInfo',
|
||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||
[GroupCode, [uid], forced],
|
||||
(ret) => ret.result === 0,
|
||||
(params, _, members) => params === GroupCode && members.size > 0 && members.has(uid),
|
||||
1,
|
||||
forced ? 2500 : 250
|
||||
);
|
||||
}, this.core.eventWrapper, GroupCode, uid, forced);
|
||||
if (data && data[3] instanceof Map && data[3].has(uid)) {
|
||||
return data[3].get(uid);
|
||||
}
|
||||
if (retry > 0) {
|
||||
let trydata = await this.getGroupMemberEx(GroupCode, uid, true, retry - 1) as GroupMember | undefined;
|
||||
if (trydata) return trydata;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
async getGroupMembersV2(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||
const groupService = this.context.session.getGroupService();
|
||||
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
|
||||
const listener = this.core.eventWrapper.registerListen(
|
||||
'NodeIKernelGroupListener/onMemberListChange',
|
||||
1,
|
||||
500,
|
||||
5000,
|
||||
(params) => params.sceneId === sceneId,
|
||||
);
|
||||
try {
|
||||
|
@@ -113,7 +113,7 @@ export class NTQQMsgApi {
|
||||
return await this.context.session.getMsgService().getMsgsBySeqList(peer, msgSeqList);
|
||||
}
|
||||
async getMsgBySeqExFirstMsg(peer: Peer, rootMsgId: string, replyMsgId: string) {
|
||||
let reply = await this.context.session.getMsgService().getSourceOfReplyMsgV2(peer, rootMsgId, replyMsgId);
|
||||
const reply = await this.context.session.getMsgService().getSourceOfReplyMsgV2(peer, rootMsgId, replyMsgId);
|
||||
console.log(reply);
|
||||
}
|
||||
async getMsgExBySeq(peer: Peer, msgSeq: string) {
|
||||
@@ -164,6 +164,18 @@ export class NTQQMsgApi {
|
||||
}, msgIds);
|
||||
}
|
||||
|
||||
async recallMsgV2(peer: Peer, msgId: string) {
|
||||
await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelMsgService/recallMsg',
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
[peer, [msgId]],
|
||||
() => true,
|
||||
(updatedList) => updatedList.find(m => m.msgId === msgId && m.recallTime !== '0') !== undefined,
|
||||
1,
|
||||
1000,
|
||||
);
|
||||
}
|
||||
|
||||
async PrepareTempChat(toUserUid: string, GroupCode: string, nickname: string) {
|
||||
return this.context.session.getMsgService().prepareTempChat({
|
||||
chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP,
|
||||
|
@@ -11,7 +11,7 @@ export default class GetGroupAddRequest extends BaseAction<null, OB11GroupReques
|
||||
actionName = ActionName.GetGroupIgnoreAddRequest;
|
||||
|
||||
async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
|
||||
const data = await this.core.apis.GroupApi.getGroupIgnoreNotifies();
|
||||
// const data = await this.core.apis.GroupApi.getGroupIgnoreNotifies();
|
||||
// log(data);
|
||||
// const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE);
|
||||
// const returnData: OB11GroupRequestNotify[] = [];
|
||||
|
@@ -26,7 +26,7 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error(`Uin2Uid Error ${payload.user_id}不存在`);
|
||||
const [member, info] = await Promise.allSettled([
|
||||
this.core.apis.GroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache),
|
||||
this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache),
|
||||
this.core.apis.UserApi.getUserDetailInfo(uid),
|
||||
]);
|
||||
if (member.status !== 'fulfilled') throw new Error(`群(${payload.group_id})成员${payload.user_id}获取失败 ${member.reason}`);
|
||||
|
@@ -3,6 +3,7 @@ import { ALLRouter } from './src/router';
|
||||
import { LogWrapper } from '@/common/log';
|
||||
import { NapCatPathWrapper } from '@/common/path';
|
||||
import { WebUiConfigWrapper } from './src/helper/config';
|
||||
import { RequestUtil } from '@/common/request';
|
||||
|
||||
const app = express();
|
||||
|
||||
@@ -38,7 +39,23 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp
|
||||
app.use(config.prefix + '/api', ALLRouter);
|
||||
app.listen(config.port, config.host, async () => {
|
||||
log(`[NapCat] [WebUi] Current WebUi is running at http://${config.host}:${config.port}${config.prefix}`);
|
||||
log(`[NapCat] [WebUi] Login URL is http://${config.host}:${config.port}${config.prefix}/webui`);
|
||||
log(`[NapCat] [WebUi] Login Token is ${config.token}`);
|
||||
log(`[NapCat] [WebUi] WebUi User Panel Url: http://${config.host}:${config.port}${config.prefix}/webui?token=${config.token}`);
|
||||
log(`[NapCat] [WebUi] WebUi Local Panel Url: http://127.0.0.1:${config.port}${config.prefix}/webui?token=${config.token}`);
|
||||
//获取上网Ip
|
||||
//https://www.ip.cn/api/index?ip&type=0
|
||||
RequestUtil.HttpGetJson<{ IP: {IP:string} }>(
|
||||
'https://ip.011102.xyz/',
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
true,
|
||||
true
|
||||
).then((data) => {
|
||||
log(`[NapCat] [WebUi] WebUi Publish Panel Url: http://${data.IP.IP}:${config.port}${config.prefix}/webui/?token=${config.token}`);
|
||||
}).catch((err) => {
|
||||
logger.logError(`[NapCat] [WebUi] Get Publish Panel Url Error: ${err}`);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V2.3.5', 'napcat-update-button', 'secondary'),
|
||||
SettingButton('V2.3.7', 'napcat-update-button', 'secondary'),
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V2.3.5", "napcat-update-button", "secondary")
|
||||
SettingButton("V2.3.7", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -29,7 +29,7 @@
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
input[type="password"] {
|
||||
width: 90%;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
@@ -64,7 +64,7 @@
|
||||
<form id="token-form" onsubmit="event.preventDefault(); submitToken();">
|
||||
<div class="input-group">
|
||||
<label for="token-input">Enter Token:</label>
|
||||
<input type="text" id="token-input" required>
|
||||
<input type="password" id="token-input" required>
|
||||
</div>
|
||||
<p class="error-message hidden" id="error-message"></p>
|
||||
<button type="submit">Login</button>
|
||||
@@ -133,4 +133,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
Reference in New Issue
Block a user