Compare commits

..

4 Commits

Author SHA1 Message Date
手瓜一十雪
3b5e6553cd chore 2024-08-23 11:04:47 +08:00
手瓜一十雪
509390af20 release: 2.2.2 2024-08-23 11:01:24 +08:00
手瓜一十雪
9ad511a9c0 release: 2.2.1 2024-08-23 10:57:13 +08:00
手瓜一十雪
89c102513d release: 2.2.0 2024-08-23 10:55:19 +08:00
20 changed files with 315 additions and 293 deletions

View File

@@ -3,33 +3,36 @@
</div>
---
## 欢迎回来
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
## To Be Continued
当前版本 (v2.1.x) 请使用内核构建版本(版本号最后的五位数)为 27187 以上的 PC NTQQ 运行
## 猫猫技能
## 项目介绍
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现。
## 项目优势
- [x] **多种启动方式**支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
- [x] **超多接口**在实现大部分Onebot接口上扩展了一套私有API
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
## 使用猫猫
## 如何使用
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
**首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程。
## 回家旅途
## 相关链接
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
## 猫猫朋友
## 鸣谢名单
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供初始版本基础
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
---
## 约法三章
## 使用许可
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。**
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 [core](./src/core) 部分代码开发。**

View File

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

View File

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

View File

@@ -162,89 +162,7 @@ export class LegacyNTEventWrapper {
this.createListenerFunction(ListenerMainName);
});
}
async CallNormalEventV2<
EventType extends (...args: any[]) => Promise<any>,
ListenerType extends (...args: any[]) => void
>(
EventName = '',
ListenerName = '',
waitTimes = 1,
timeout: number = 3000,
checkerEvent: (ret: Awaited<ReturnType<EventType>>) => boolean = () => true,
checkerListener: (...args: Parameters<ListenerType>) => boolean = () => true,
...args: Parameters<EventType>
) {
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
async (resolve, reject) => {
const id = randomUUID();
let complete = 0;
let retData: Parameters<ListenerType> | undefined = undefined;
let retEvent: any = {};
const databack = () => {
if (complete == 0) {
reject(
new Error(
'Timeout: NTEvent EventName:' +
EventName +
' ListenerName:' +
ListenerName +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n',
),
);
} else {
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
}
};
const ListenerNameList = ListenerName.split('/');
const ListenerMainName = ListenerNameList[0];
const ListenerSubName = ListenerNameList[1];
const Timeouter = setTimeout(databack, timeout);
const eventCallbak = {
timeout: timeout,
createtime: Date.now(),
checker: checkerListener,
func: (...args: any[]) => {
complete++;
//console.log('func', ...args);
retData = args as Parameters<ListenerType>;
if (complete >= waitTimes) {
clearTimeout(Timeouter);
databack();
}
},
};
if (!this.EventTask.get(ListenerMainName)) {
this.EventTask.set(ListenerMainName, new Map());
}
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
}
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
this.createListenerFunction(ListenerMainName);
const EventFunc = this.createEventFunction<EventType>(EventName);
retEvent = await EventFunc!(...(args as any[]));
if(!checkerEvent(retEvent)){
clearTimeout(Timeouter);
reject(
new Error(
'EventChecker Failed: NTEvent EventName:' +
EventName +
' ListenerName:' +
ListenerName +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n',
),
);
}
},
);
}
async CallNormalEvent<
EventType extends (...args: any[]) => Promise<any>,
ListenerType extends (...args: any[]) => void

View File

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

View File

@@ -1,5 +1,5 @@
import { Friend, FriendV2, User } from '@/core/entities';
import { BuddyListReqType, InstanceContext, NapCatCore, NodeIKernelBuddyListener, NodeIKernelBuddyService, NodeIKernelProfileService, OnBuddyChangeParams } from '@/core';
import { BuddyListReqType, InstanceContext, NapCatCore, NodeIKernelProfileService, OnBuddyChangeParams } from '@/core';
import { LimitedHashTable } from '@/common/utils/MessageUnique';
export class NTQQFriendApi {
@@ -70,14 +70,29 @@ export class NTQQFriendApi {
async isBuddy(uid: string) {
return this.context.session.getBuddyService().isBuddy(uid);
}
async clearBuddyReqUnreadCnt() {
return this.context.session.getBuddyService().clearBuddyReqUnreadCnt();
}
async getBuddyReq() {
const [, ret] = await this.core.eventWrapper.CallNormalEventV2
<NodeIKernelBuddyService['getBuddyReq'], NodeIKernelBuddyListener['onBuddyReqChange']>
('NodeIKernelBuddyService/getBuddyReq', 'NodeIKernelBuddyListener/onBuddyReqChange', 1, 5000);
return ret;
/**
* @deprecated
* @param forced
* @returns
*/
async getFriends(forced = false): Promise<User[]> {
const [_retData, _BuddyArg] = await this.core.eventWrapper.CallNormalEvent<(force: boolean) => Promise<any>, (arg: OnBuddyChangeParams) => void>
(
'NodeIKernelBuddyService/getBuddyList',
'NodeIKernelBuddyListener/onBuddyListChange',
1,
5000,
() => true,
forced,
);
const friends: User[] = [];
for (const categoryItem of _BuddyArg) {
for (const friend of categoryItem.buddyList) {
friends.push(friend);
}
}
return friends;
}
async handleFriendRequest(flag: string, accept: boolean) {

View File

@@ -7,8 +7,6 @@ import {
GroupNotify,
GroupRequestOperateTypes,
InstanceContext,
KickMemberInfo,
kickMemberV2Req,
MemberExtSourceType,
NapCatCore,
NodeIKernelGroupListener,
@@ -44,12 +42,12 @@ export class NTQQGroupApi {
type ListenerType = NodeIKernelGroupListener['onGroupListUpdate'];
const [_retData, _updateType, groupList] = await this.core.eventWrapper.CallNormalEvent<(force: boolean) => Promise<any>, ListenerType>
(
'NodeIKernelGroupService/getGroupList',
'NodeIKernelGroupListener/onGroupListUpdate',
1,
5000,
() => true,
forced,
'NodeIKernelGroupService/getGroupList',
'NodeIKernelGroupListener/onGroupListUpdate',
1,
5000,
() => true,
forced,
);
return groupList;
}
@@ -221,17 +219,7 @@ export class NTQQGroupApi {
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
return this.context.session.getGroupService().addGroupEssence(param);
}
async kickMemberV2Inner(param: kickMemberV2Req) {
return this.context.session.getGroupService().kickMemberV2(param);
}
async quitGroupV2(GroupCode: string, needDeleteLocalMsg: boolean) {
let param = {
groupCode: GroupCode,
needDeleteLocalMsg: needDeleteLocalMsg
};
//应该是直接返回不需要Listener的 未经测试 需测试再发布
return this.context.session.getGroupService().quitGroupV2(param);
}
async removeGroupEssence(GroupCode: string, msgId: string) {
// 代码没测过
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
@@ -252,14 +240,14 @@ export class NTQQGroupApi {
async getSingleScreenNotifies(num: number) {
const [_retData, _doubt, _seq, notifies] = await this.core.eventWrapper.CallNormalEvent<(arg1: boolean, arg2: string, arg3: number) => Promise<any>, (doubt: boolean, seq: string, notifies: GroupNotify[]) => void>
(
'NodeIKernelGroupService/getSingleScreenNotifies',
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
1,
5000,
() => true,
false,
'',
num,
'NodeIKernelGroupService/getSingleScreenNotifies',
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
1,
5000,
() => true,
false,
'',
num,
);
return notifies;
}
@@ -271,12 +259,12 @@ export class NTQQGroupApi {
//return napCatCore.session.getGroupService().getMemberInfo(GroupCode, [uid], forced);
const Listener = this.core.eventWrapper.RegisterListen<(params: any) => void>
(
'NodeIKernelGroupListener/onMemberInfoChange',
1,
forced ? 5000 : 250,
(params) => {
return params === GroupCode;
},
'NodeIKernelGroupListener/onMemberInfoChange',
1,
forced ? 5000 : 250,
(params) => {
return params === GroupCode;
},
);
const EventFunc = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelGroupService/getMemberInfo');
const retData = await EventFunc!(GroupCode, [uid], forced);
@@ -345,7 +333,7 @@ export class NTQQGroupApi {
'NodeIKernelGroupService/getGroupRecommendContactArkJson',
5000,
GroupCode,
);
);
return ret.arkJson;
}

View File

@@ -20,14 +20,15 @@ export class NTQQWebApi {
async shareDigest(groupCode: string, msgSeq: string, msgRandom: string, targetGroupCode: string) {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const url = `https://qun.qq.com/cgi-bin/group_digest/share_digest?${new URLSearchParams({
bkn: this.getBknFromCookie(cookieObject),
group_code: groupCode,
msg_seq: msgSeq,
msg_random: msgRandom,
target_group_code: targetGroupCode,
}).toString()
}`;
const url = `https://qun.qq.com/cgi-bin/group_digest/share_digest?${
new URLSearchParams({
bkn: this.getBknFromCookie(cookieObject),
group_code: groupCode,
msg_seq: msgSeq,
msg_random: msgRandom,
target_group_code: targetGroupCode,
}).toString()
}`;
try {
return RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
} catch (e) {
@@ -37,17 +38,18 @@ export class NTQQWebApi {
async getGroupEssenceMsg(GroupCode: string, page_start: string) {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?${new URLSearchParams({
bkn: this.getBknFromCookie(cookieObject),
group_code: GroupCode,
page_start,
page_limit: '20',
}).toString()
}`;
const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?${
new URLSearchParams({
bkn: this.getBknFromCookie(cookieObject),
group_code: GroupCode,
page_start,
page_limit: '20',
}).toString()
}`;
let ret;
try {
ret = await RequestUtil.HttpGetJson<GroupEssenceMsgRet>
(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
} catch {
return undefined;
}
@@ -63,14 +65,15 @@ export class NTQQWebApi {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const retList: Promise<WebApiGroupMemberRet>[] = [];
const fastRet = await RequestUtil.HttpGetJson<WebApiGroupMemberRet>
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${
new URLSearchParams({
st: '0',
end: '40',
sort: '1',
gc: GroupCode,
bkn: this.getBknFromCookie(cookieObject),
}).toString()
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) {
return [];
} else {
@@ -83,14 +86,15 @@ export class NTQQWebApi {
//遍历批量请求
for (let i = 2; i <= PageNum; i++) {
const ret = RequestUtil.HttpGetJson<WebApiGroupMemberRet>
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${
new URLSearchParams({
st: ((i - 1) * 40).toString(),
end: (i * 40).toString(),
sort: '1',
gc: GroupCode,
bkn: this.getBknFromCookie(cookieObject),
}).toString()
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
retList.push(ret);
}
//批量等待
@@ -123,7 +127,8 @@ export class NTQQWebApi {
let ret: any = undefined;
try {
ret = await RequestUtil.HttpGetJson<any>
(`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${new URLSearchParams({
(`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${
new URLSearchParams({
bkn: this.getBknFromCookie(cookieObject),
qid: GroupCode,
text: Content,
@@ -131,7 +136,7 @@ export class NTQQWebApi {
type: '1',
settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}',
}).toString()
}`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
}`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
return ret;
} catch (e) {
return undefined;
@@ -142,10 +147,15 @@ export class NTQQWebApi {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
let ret: WebApiGroupNoticeRet | undefined = undefined;
try {
const url = 'https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=' +
this.getBknFromCookie(cookieObject) + '&qid=' + GroupCode + '&ft=23&ni=1&n=1&i=1&log_read=1&platform=1&s=-1&n=20';
ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(`https://web.qun.qq.com/cgi-bin/announce/get_t_list?${
new URLSearchParams({
bkn: this.getBknFromCookie(cookieObject),
qid: GroupCode,
type: '1',
start: '0',
num: '1',
}).toString()
}`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
if (ret?.ec !== 0) {
return undefined;
}
@@ -158,11 +168,12 @@ export class NTQQWebApi {
async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const getDataInternal = async (Internal_groupCode: string, Internal_type: number) => {
const url = `https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
gc: Internal_groupCode,
type: Internal_type.toString(),
}).toString()
}`;
const url = `https://qun.qq.com/interactive/honorlist?${
new URLSearchParams({
gc: Internal_groupCode,
type: Internal_type.toString(),
}).toString()
}`;
let resJson;
try {
const res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });

View File

@@ -1,17 +1,5 @@
import { QQLevel, Sex, User } from './user';
export interface KickMemberInfo {
optFlag: number,
optOperate: number,
optMemberUid: string,
optBytesMsg: string,
}
export interface kickMemberV2Req{
groupCode: string,
kickFlag: number,
kickList: Array<KickMemberInfo>,
kickListUids: Array<string>,
kickMsg: string
}
export enum GroupListUpdateType {
REFRESHALL,
GETALL,

View File

@@ -1,58 +1,40 @@
export enum GroupNotifyMsgType {
UN_SPECIFIED,
INVITED_BY_MEMBER,
REFUSE_INVITED,
REFUSED_BY_ADMINI_STRATOR,
AGREED_TOJOIN_DIRECT,// 有人接受了邀请入群
INVITED_NEED_ADMINI_STRATOR_PASS,
AGREED_TO_JOIN_BY_ADMINI_STRATOR,
REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS,
SET_ADMIN,
KICK_MEMBER_NOTIFY_ADMIN,
KICK_MEMBER_NOTIFY_KICKED,
MEMBER_LEAVE_NOTIFY_ADMIN,// 主动退出
CANCEL_ADMIN_NOTIFY_CANCELED,
CANCEL_ADMIN_NOTIFY_ADMIN,// 其他人取消管理员
TRANSFER_GROUP_NOTIFY_OLDOWNER,
TRANSFER_GROUP_NOTIFY_ADMIN
export enum GroupNotifyTypes {
INVITE_ME = 1,
INVITED_JOIN = 4, // 有人接受了邀请入群
JOIN_REQUEST = 7,
ADMIN_SET = 8,
KICK_MEMBER = 9,
MEMBER_EXIT = 11, // 主动退出
ADMIN_UNSET = 12,
ADMIN_UNSET_OTHER = 13, // 其他人取消管理员
}
export interface GroupNotifies {
doubt: boolean;
nextStartSeq: string;
notifies: GroupNotify[];
}
export enum GroupNotifyMsgStatus {
KINIT,//初始化
KUNHANDLE,//未处理
KAGREED,//同意
KREFUSED,//拒绝
KIGNORED//忽略
}
export enum GroupInviteStatus {
INIT,
WAIT_TO_APPROVE,
JOINED,
REFUSED_BY_ADMINI_STRATOR
}
export enum GroupInviteType {
BYBUDDY,
BYGROUPMEMBER,
BYDISCUSSMEMBER
export enum GroupNotifyStatus {
IGNORE = 0,
WAIT_HANDLE = 1,
APPROVE = 2,
REJECT = 3
}
export interface GroupNotify {
seq: string; // 通知序列号
type: GroupNotifyMsgType;
status: GroupNotifyMsgStatus;
time: number; // 自己添加的字段,时间戳,毫秒, 用于判断收到短时间内收到重复的notify
seq: string; // 唯一标识符转成数字再除以1000应该就是时间戳
type: GroupNotifyTypes;
status: GroupNotifyStatus; // 0是已忽略1是未处理2是已同意
group: { groupCode: string; groupName: string };
user1: { uid: string; nickName: string }; // 被设置管理员的人
user2: { uid: string; nickName: string }; // 操作者
actionUser: { uid: string; nickName: string }; //未知
actionTime: string;
invitationExt: {
srcType: GroupInviteType; // 邀请来源
groupCode: string;
waitStatus: GroupInviteStatus
srcType: number; // 0?未知
groupCode: string; waitStatus: number
};
postscript: string; // 加群用户填写的验证信息
repeatSeqs: [];
@@ -82,7 +64,6 @@ export enum BuddyReqType {
}
export interface FriendRequest {
isBuddy?: boolean;
isInitiator?: boolean;
isDecide: boolean;
friendUid: string;

View File

@@ -61,11 +61,11 @@ export interface NodeIKernelBuddyService {
getBuddyReqUnreadCnt(): number;
getBuddyReq(): Promise<GeneralCallResult>;
getBuddyReq(): unknown;
delBuddyReq(uid: number): void;
clearBuddyReqUnreadCnt(): Promise<GeneralCallResult>;
clearBuddyReqUnreadCnt(): void;
reqToAddFriends(uid: number, msg: string): void;

View File

@@ -3,18 +3,14 @@ import {
GroupExtParam,
GroupMember,
GroupMemberRole,
GroupNotifyMsgType,
GroupNotifyTypes,
GroupRequestOperateTypes,
kickMemberV2Req,
} from '@/core/entities';
import { GeneralCallResult } from '@/core/services/common';
//高版本的接口不应该随意使用 使用应该严格进行pr审核 同时部分ipc中未出现的接口不要过于依赖 应该做好数据兜底
export interface NodeIKernelGroupService {
kickMemberV2(param: kickMemberV2Req): Promise<GeneralCallResult>;
quitGroupV2(param: { groupCode: string; needDeleteLocalMsg: boolean; }): Promise<GeneralCallResult>;
getMemberCommonInfo(Req: {
groupCode: string,
startUin: string,
@@ -199,7 +195,7 @@ export interface NodeIKernelGroupService {
operateType: GroupRequestOperateTypes, // 2 拒绝
targetMsg: {
seq: string, // 通知序列号
type: GroupNotifyMsgType,
type: GroupNotifyTypes,
groupCode: string,
postscript: string
}

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,3 @@
import { GroupNotifyMsgStatus } from '@/core';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
@@ -29,7 +28,7 @@ export class GetGroupSystemMsg extends BaseAction<void, any> {
invitor_nick: SSNotify.user1?.nickName,
group_id: SSNotify.group?.groupCode,
group_name: SSNotify.group?.groupName,
checked: SSNotify.status === GroupNotifyMsgStatus.KUNHANDLE ? false : true,
checked: SSNotify.status === 1 ? false : true,
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
});
} else if (SSNotify.type == 7) {
@@ -39,7 +38,7 @@ export class GetGroupSystemMsg extends BaseAction<void, any> {
requester_nick: SSNotify.user1?.nickName,
group_id: SSNotify.group?.groupCode,
group_name: SSNotify.group?.groupName,
checked: SSNotify.status === GroupNotifyMsgStatus.KUNHANDLE ? false : true,
checked: SSNotify.status === 1 ? false : true,
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
});
}

View File

@@ -171,7 +171,7 @@ const _handlers: {
} else {
postData = data;
}
// Mlikiowa V2.2.6 Refactor Todo
// Mlikiowa V2.2.2 Refactor Todo
const signUrl = obContext.configLoader.configData.musicSignUrl;
if (!signUrl) {
if (data.type === 'qq') {

View File

@@ -90,7 +90,6 @@ async function createContext(coreContext: NapCatCore, payload: OB11PostSendMsg,
// This redundant design of Ob11 here should be blamed.
const NTQQFriendApi = coreContext.apis.FriendApi;
const NTQQUserApi = coreContext.apis.UserApi;
const NTQQMsgApi = coreContext.apis.MsgApi;
if ((contextMode === ContextMode.Group || contextMode === ContextMode.Normal) && payload.group_id) {
return {
chatType: ChatType.KCHATTYPEGROUP,
@@ -99,34 +98,12 @@ async function createContext(coreContext: NapCatCore, payload: OB11PostSendMsg,
}
if ((contextMode === ContextMode.Private || contextMode === ContextMode.Normal) && payload.user_id) {
const Uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
if (!Uid) throw '无法获取用户信息';
const isBuddy = await NTQQFriendApi.isBuddy(Uid);
if (!isBuddy) {
const ret = await NTQQMsgApi.getTempChatInfo(ChatType.KCHATTYPETEMPC2CFROMGROUP, Uid);
if (ret.tmpChatInfo?.groupCode) {
return {
chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP,
peerUid: Uid,
guildId: '',
};
}
if (payload.group_id) {
return {
chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP,
peerUid: Uid,
guildId: payload.group_id.toString(),
};
}
return {
chatType: ChatType.KCHATTYPEC2C,
peerUid: Uid!,
guildId: '',
};
}
const isBuddy = await NTQQFriendApi.isBuddy(Uid!);
//console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy);
return {
chatType: ChatType.KCHATTYPEC2C,
chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP,
peerUid: Uid!,
guildId: '',
guildId: payload.group_id?.toString() || '',
};
}
throw '请指定 group_id 或 user_id';
@@ -158,7 +135,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
if (payload.user_id && payload.message_type !== 'group') {
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
const isBuddy = await NTQQFriendApi.isBuddy(uid!);
if (!isBuddy) { }
if (!isBuddy) {}
}
return { valid: true };
}

View File

@@ -65,12 +65,11 @@ export class OneBotMsgApi {
name = content.replace('@', '');
}
}
message_data = {
type: OB11MessageDataType.at,
data: {
qq: qq!,
//name,
name,
},
};
return message_data;

View File

@@ -3,14 +3,13 @@ import {
BuddyReqType,
ChatType,
GroupListener,
GroupNotifyTypes,
InstanceContext,
MsgListener,
NapCatCore,
RawMessage,
SendStatusType,
GroupMemberRole,
GroupNotifyMsgType,
GroupNotifyMsgStatus,
} from '@/core';
import { OB11Config, OB11ConfigLoader } from '@/onebot/helper/config';
import { OneBotApiContextType } from '@/onebot/types';
@@ -284,16 +283,8 @@ export class NapCatOneBot11Adapter {
private initBuddyListener() {
const buddyListener = new BuddyListener();
buddyListener.onBuddyReqChange = async reqs => {
this.core.apis.FriendApi.clearBuddyReqUnreadCnt();
for (let i = 0; i < reqs.unreadNums; i++) {
const req = reqs.buddyReqs[i];
//req.isBuddy === false是单向好友 null为常规情况
// if (req.isBuddy === false && ) {
// const NTQQFriendApi = this.core.apis.FriendApi;
// await NTQQFriendApi.handleFriendRequest(req.friendUid + '|' + req.reqTime, true);
// }
buddyListener.onBuddyReqChange = reqs => {
reqs.buddyReqs.forEach(async req => {
if (!!req.isInitiator || (req.isDecide && req.reqType !== BuddyReqType.KMEINITIATORWAITPEERCONFIRM)) {
return;
}
@@ -308,7 +299,7 @@ export class NapCatOneBot11Adapter {
} catch (e) {
this.context.logger.logDebug('获取加好友者QQ号失败', e);
}
}
});
};
this.context.session.getBuddyService().addKernelBuddyListener(
@@ -322,11 +313,12 @@ export class NapCatOneBot11Adapter {
groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
//console.log('ob11 onGroupNotifiesUpdated', notifies[0]);
if (![
GroupNotifyMsgType.SET_ADMIN,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
GroupNotifyTypes.ADMIN_SET,
GroupNotifyTypes.ADMIN_UNSET,
GroupNotifyTypes.ADMIN_UNSET_OTHER,
].includes(notifies[0]?.type)) {
for (const notify of notifies) {
notify.time = Date.now();
const notifyTime = parseInt(notify.seq) / 1000 / 1000;
// log(`群通知时间${notifyTime}`, `启动时间${this.bootTime}`);
if (notifyTime < this.bootTime) {
@@ -337,9 +329,9 @@ export class NapCatOneBot11Adapter {
this.context.logger.logDebug('收到群通知', notify);
if ([
GroupNotifyMsgType.SET_ADMIN,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN,
GroupNotifyTypes.ADMIN_SET,
GroupNotifyTypes.ADMIN_UNSET,
GroupNotifyTypes.ADMIN_UNSET_OTHER,
].includes(notify.type)) {
const member1 = await this.core.apis.GroupApi.getGroupMember(notify.group.groupCode, notify.user1.uid);
this.context.logger.logDebug('有管理员变动通知');
@@ -348,21 +340,20 @@ export class NapCatOneBot11Adapter {
this.context.logger.logDebug('开始获取变动的管理员');
if (member1) {
this.context.logger.logDebug('变动管理员获取成功');
// member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal;
const groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent(
this.core,
parseInt(notify.group.groupCode),
parseInt(member1.uin),
[
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_CANCELED,
GroupNotifyMsgType.CANCEL_ADMIN_NOTIFY_ADMIN
].includes(notify.type) ? 'unset' : 'set',
[GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(notify.type) ? 'unset' : 'set',
);
this.networkManager.emitEvent(groupAdminNoticeEvent)
.catch(e => this.context.logger.logError('处理群管理员变动失败', e));
} else {
this.context.logger.logDebug('获取群通知的成员信息失败', notify, this.core.apis.GroupApi.getGroup(notify.group.groupCode));
}
} else if (notify.type == GroupNotifyMsgType.MEMBER_LEAVE_NOTIFY_ADMIN || notify.type == GroupNotifyMsgType.KICK_MEMBER_NOTIFY_ADMIN) {
} else if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) {
this.context.logger.logDebug('有成员退出通知', notify);
const member1Uin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid))!;
let operatorId = member1Uin;
@@ -386,8 +377,8 @@ export class NapCatOneBot11Adapter {
.catch(e => this.context.logger.logError('处理群成员退出失败', e));
// notify.status == 1 表示未处理 2表示处理完成
} else if ([
GroupNotifyMsgType.REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS,
].includes(notify.type) && notify.status == GroupNotifyMsgStatus.KUNHANDLE) {
GroupNotifyTypes.JOIN_REQUEST,
].includes(notify.type) && notify.status == 1) {
this.context.logger.logDebug('有加群请求');
try {
let requestUin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid))!;
@@ -407,7 +398,7 @@ export class NapCatOneBot11Adapter {
} catch (e) {
this.context.logger.logError('获取加群人QQ号失败 Uid:', notify.user1.uid, e);
}
} else if (notify.type == GroupNotifyMsgType.INVITED_BY_MEMBER && notify.status == GroupNotifyMsgStatus.KUNHANDLE) {
} else if (notify.type == GroupNotifyTypes.INVITE_ME && notify.status == 1) {
this.context.logger.logDebug(`收到邀请我加群通知:${notify}`);
const groupInviteEvent = new OB11GroupRequestEvent(
this.core,

View File

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

View File

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